X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;ds=sidebyside;f=gtk%2Fgtkplug.c;h=5bb003afc00a8f57b4319f92e357c4b469ae8794;hb=0a8043da1386ea35a2c0fa5fcf762ef0296520d6;hp=74b4f2a12ecdb2a0a08bfaa14b4c5c8004685081;hpb=4127a267f19bc152e7d421c1363a204758fd29b3;p=~andy%2Fgtk diff --git a/gtk/gtkplug.c b/gtk/gtkplug.c index 74b4f2a12..5bb003afc 100644 --- a/gtk/gtkplug.c +++ b/gtk/gtkplug.c @@ -25,18 +25,41 @@ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ +#include "config.h" + #include "gtkmain.h" #include "gtkmarshalers.h" #include "gtkplug.h" +#include "gtkintl.h" #include "gtkprivate.h" +#include "gtkplugprivate.h" -#include "gdk/gdkkeysyms.h" -#include "x11/gdkx.h" - -#include "xembed.h" +/** + * SECTION:gtkplug + * @Short_description: Toplevel for embedding into other processes + * @Title: GtkPlug + * @See_also: #GtkSocket + * + * Together with #GtkSocket, #GtkPlug provides the ability + * to embed widgets from one process into another process + * in a fashion that is transparent to the user. One + * process creates a #GtkSocket widget and passes the + * ID of that widget's window to the other process, + * which then creates a #GtkPlug with that window ID. + * Any widgets contained in the #GtkPlug then will appear + * inside the first application's window. + * + * + * The #GtkPlug and #GtkSocket widgets are currently not available + * on all platforms supported by GTK+. + * + */ -static void gtk_plug_class_init (GtkPlugClass *klass); -static void gtk_plug_init (GtkPlug *plug); +static void gtk_plug_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void gtk_plug_finalize (GObject *object); static void gtk_plug_realize (GtkWidget *widget); static void gtk_plug_unrealize (GtkWidget *widget); static void gtk_plug_show (GtkWidget *widget); @@ -47,39 +70,29 @@ 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, - GdkEventKey *event); +static gboolean gtk_plug_focus_event (GtkWidget *widget, + GdkEventFocus *event); 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); -#if 0 -static void gtk_plug_accel_entries_changed (GtkWindow *window); -#endif -static GdkFilterReturn gtk_plug_filter_func (GdkXEvent *gdk_xevent, - GdkEvent *event, - gpointer data); - -#if 0 -static void gtk_plug_free_grabbed_keys (GHashTable *key_table); -#endif -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 void gtk_plug_keys_changed (GtkWindow *window); + static GtkBinClass *bin_class = NULL; +typedef struct +{ + guint accelerator_key; + GdkModifierType accelerator_mods; +} GrabbedKey; + +enum { + PROP_0, + PROP_EMBEDDED, + PROP_SOCKET_WINDOW +}; + enum { EMBEDDED, LAST_SIGNAL @@ -87,45 +100,48 @@ enum { static guint plug_signals[LAST_SIGNAL] = { 0 }; -GtkType -gtk_plug_get_type () +G_DEFINE_TYPE (GtkPlug, gtk_plug, GTK_TYPE_WINDOW) + +static void +gtk_plug_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { - static GtkType plug_type = 0; + GtkPlug *plug = GTK_PLUG (object); - if (!plug_type) + switch (prop_id) { - static const GTypeInfo plug_info = - { - sizeof (GtkPlugClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gtk_plug_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GtkPlug), - 16, /* n_preallocs */ - (GInstanceInitFunc) gtk_plug_init, - }; - - plug_type = g_type_register_static (GTK_TYPE_WINDOW, "GtkPlug", &plug_info, 0); + case PROP_EMBEDDED: + g_value_set_boolean (value, plug->socket_window != NULL); + break; + case PROP_SOCKET_WINDOW: + g_value_set_object (value, plug->socket_window); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } - - return plug_type; } static void gtk_plug_class_init (GtkPlugClass *class) { + GObjectClass *gobject_class = (GObjectClass *)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); + bin_class = g_type_class_peek (GTK_TYPE_BIN); + gobject_class->get_property = gtk_plug_get_property; + gobject_class->finalize = gtk_plug_finalize; + 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_in_event = gtk_plug_focus_event; + widget_class->focus_out_event = gtk_plug_focus_event; widget_class->show = gtk_plug_show; widget_class->hide = gtk_plug_hide; @@ -138,18 +154,52 @@ gtk_plug_class_init (GtkPlugClass *class) container_class->check_resize = gtk_plug_check_resize; window_class->set_focus = gtk_plug_set_focus; -#if 0 - window_class->accel_entries_changed = gtk_plug_accel_entries_changed; -#endif - + window_class->keys_changed = gtk_plug_keys_changed; + + /** + * GtkPlug:embedded: + * + * %TRUE if the plug is embedded in a socket. + * + * Since: 2.12 + */ + g_object_class_install_property (gobject_class, + PROP_EMBEDDED, + g_param_spec_boolean ("embedded", + P_("Embedded"), + P_("Whether or not the plug is embedded"), + FALSE, + GTK_PARAM_READABLE)); + + /** + * GtkPlug:socket-window: + * + * The window of the socket the plug is embedded in. + * + * Since: 2.14 + */ + g_object_class_install_property (gobject_class, + PROP_SOCKET_WINDOW, + g_param_spec_object ("socket-window", + P_("Socket Window"), + P_("The window of the socket the plug is embedded in"), + GDK_TYPE_WINDOW, + GTK_PARAM_READABLE)); + + /** + * GtkPlug::embedded: + * @plug: the object on which the signal was emitted + * + * Gets emitted when the plug becomes embedded in a socket. + */ plug_signals[EMBEDDED] = - g_signal_new ("embedded", + g_signal_new (I_("embedded"), G_OBJECT_CLASS_TYPE (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GtkPlugClass, embedded), NULL, NULL, _gtk_marshal_VOID__VOID, - GTK_TYPE_NONE, 0); + G_TYPE_NONE, 0); } static void @@ -171,7 +221,7 @@ gtk_plug_set_is_child (GtkPlug *plug, if (is_child) { if (plug->modality_window) - handle_modality_off (plug); + _gtk_plug_handle_modality_off (plug); if (plug->modality_group) { @@ -185,227 +235,377 @@ gtk_plug_set_is_child (GtkPlug *plug, * here, but don't bother remapping -- we will get mapped * by gtk_widget_set_parent (). */ - if (GTK_WIDGET_MAPPED (plug)) + if (gtk_widget_get_mapped (GTK_WIDGET (plug))) gtk_widget_unmap (GTK_WIDGET (plug)); - GTK_WIDGET_UNSET_FLAGS (plug, GTK_TOPLEVEL); + _gtk_window_set_is_toplevel (GTK_WINDOW (plug), FALSE); gtk_container_set_resize_mode (GTK_CONTAINER (plug), GTK_RESIZE_PARENT); _gtk_widget_propagate_hierarchy_changed (GTK_WIDGET (plug), GTK_WIDGET (plug)); } else { + if (GTK_WINDOW (plug)->focus_widget) + gtk_window_set_focus (GTK_WINDOW (plug), NULL); + if (GTK_WINDOW (plug)->default_widget) + gtk_window_set_default (GTK_WINDOW (plug), NULL); + plug->modality_group = gtk_window_group_new (); gtk_window_group_add_window (plug->modality_group, GTK_WINDOW (plug)); - GTK_WIDGET_SET_FLAGS (plug, GTK_TOPLEVEL); + _gtk_window_set_is_toplevel (GTK_WINDOW (plug), TRUE); gtk_container_set_resize_mode (GTK_CONTAINER (plug), GTK_RESIZE_QUEUE); _gtk_widget_propagate_hierarchy_changed (GTK_WIDGET (plug), NULL); } } +/** + * gtk_plug_get_id: + * @plug: a #GtkPlug. + * + * Gets the window ID of a #GtkPlug widget, which can then + * be used to embed this window inside another window, for + * instance with gtk_socket_add_id(). + * + * Return value: the window ID for the plug + **/ +GdkNativeWindow +gtk_plug_get_id (GtkPlug *plug) +{ + g_return_val_if_fail (GTK_IS_PLUG (plug), 0); + + if (!gtk_widget_get_realized (GTK_WIDGET (plug))) + gtk_widget_realize (GTK_WIDGET (plug)); + + return _gtk_plug_windowing_get_id (plug); +} + +/** + * gtk_plug_get_embedded: + * @plug: a #GtkPlug + * + * Determines whether the plug is embedded in a socket. + * + * Return value: %TRUE if the plug is embedded in a socket + * + * Since: 2.14 + **/ +gboolean +gtk_plug_get_embedded (GtkPlug *plug) +{ + g_return_val_if_fail (GTK_IS_PLUG (plug), FALSE); + + return plug->socket_window != NULL; +} + +/** + * gtk_plug_get_socket_window: + * @plug: a #GtkPlug + * + * Retrieves the socket the plug is embedded in. + * + * Return value: the window of the socket, or %NULL + * + * Since: 2.14 + **/ +GdkWindow * +gtk_plug_get_socket_window (GtkPlug *plug) +{ + g_return_val_if_fail (GTK_IS_PLUG (plug), NULL); + + return plug->socket_window; +} + /** * _gtk_plug_add_to_socket: * @plug: a #GtkPlug - * @socket: a #GtkSocket + * @socket_: a #GtkSocket * * Adds a plug to a socket within the same application. **/ void _gtk_plug_add_to_socket (GtkPlug *plug, - GtkSocket *socket) + GtkSocket *socket_) { GtkWidget *widget; + gint w, h; g_return_if_fail (GTK_IS_PLUG (plug)); - g_return_if_fail (GTK_IS_SOCKET (socket)); - g_return_if_fail (GTK_WIDGET_REALIZED (socket)); + g_return_if_fail (GTK_IS_SOCKET (socket_)); + g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (socket_))); widget = GTK_WIDGET (plug); gtk_plug_set_is_child (plug, TRUE); plug->same_app = TRUE; - socket->same_app = TRUE; - socket->plug_widget = widget; + socket_->same_app = TRUE; + socket_->plug_widget = widget; - plug->socket_window = GTK_WIDGET (socket)->window; + plug->socket_window = GTK_WIDGET (socket_)->window; + g_object_ref (plug->socket_window); + g_signal_emit (plug, plug_signals[EMBEDDED], 0); + g_object_notify (G_OBJECT (plug), "embedded"); - if (GTK_WIDGET_REALIZED (widget)) - gdk_window_reparent (widget->window, plug->socket_window, 0, 0); + if (gtk_widget_get_realized (widget)) + { + gdk_drawable_get_size (GDK_DRAWABLE (widget->window), &w, &h); + gdk_window_reparent (widget->window, plug->socket_window, -w, -h); + } - gtk_widget_set_parent (widget, GTK_WIDGET (socket)); + gtk_widget_set_parent (widget, GTK_WIDGET (socket_)); - g_signal_emit_by_name (G_OBJECT (socket), "plug_added", 0); + g_signal_emit_by_name (socket_, "plug-added"); +} + +/** + * _gtk_plug_send_delete_event: + * @widget: a #GtkWidget + * + * Send a GDK_DELETE event to the @widget and destroy it if + * necessary. Internal GTK function, called from this file or the + * backend-specific GtkPlug implementation. + */ +void +_gtk_plug_send_delete_event (GtkWidget *widget) +{ + GdkEvent *event = gdk_event_new (GDK_DELETE); + + event->any.window = g_object_ref (widget->window); + event->any.send_event = FALSE; + + g_object_ref (widget); + + if (!gtk_widget_event (widget, event)) + gtk_widget_destroy (widget); + + g_object_unref (widget); + + gdk_event_free (event); } /** * _gtk_plug_remove_from_socket: * @plug: a #GtkPlug - * @socket: a #GtkSocket + * @socket_: a #GtkSocket * * Removes a plug from a socket within the same application. **/ void _gtk_plug_remove_from_socket (GtkPlug *plug, - GtkSocket *socket) + GtkSocket *socket_) { GtkWidget *widget; - GdkEvent event; gboolean result; gboolean widget_was_visible; g_return_if_fail (GTK_IS_PLUG (plug)); - g_return_if_fail (GTK_IS_SOCKET (socket)); - g_return_if_fail (GTK_WIDGET_REALIZED (plug)); + g_return_if_fail (GTK_IS_SOCKET (socket_)); + g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (plug))); widget = GTK_WIDGET (plug); + if (GTK_WIDGET_IN_REPARENT (widget)) + return; + g_object_ref (plug); - g_object_ref (socket); + g_object_ref (socket_); - widget_was_visible = GTK_WIDGET_VISIBLE (plug); + widget_was_visible = gtk_widget_get_visible (widget); gdk_window_hide (widget->window); - gdk_window_reparent (widget->window, GDK_ROOT_PARENT (), 0, 0); - GTK_PRIVATE_SET_FLAG (plug, GTK_IN_REPARENT); + gdk_window_reparent (widget->window, + gtk_widget_get_root_window (widget), + 0, 0); gtk_widget_unparent (GTK_WIDGET (plug)); GTK_PRIVATE_UNSET_FLAG (plug, GTK_IN_REPARENT); - socket->plug_widget = NULL; - socket->plug_window = NULL; - socket->same_app = FALSE; + socket_->plug_widget = NULL; + if (socket_->plug_window != NULL) + { + g_object_unref (socket_->plug_window); + socket_->plug_window = NULL; + } + + socket_->same_app = FALSE; plug->same_app = FALSE; - plug->socket_window = NULL; - + if (plug->socket_window != NULL) + { + g_object_unref (plug->socket_window); + plug->socket_window = NULL; + } gtk_plug_set_is_child (plug, FALSE); - - g_signal_emit_by_name (G_OBJECT (socket), "plug_removed", &result); + + g_signal_emit_by_name (socket_, "plug-removed", &result); if (!result) - gtk_widget_destroy (GTK_WIDGET (socket)); + gtk_widget_destroy (GTK_WIDGET (socket_)); + + if (widget->window) + _gtk_plug_send_delete_event (widget); - event.any.type = GDK_DELETE; - event.any.window = g_object_ref (widget->window); - event.any.send_event = FALSE; - - if (!gtk_widget_event (widget, &event)) - gtk_widget_destroy (widget); - - g_object_unref (event.any.window); g_object_unref (plug); - if (widget_was_visible && GTK_WIDGET_VISIBLE (socket)) - gtk_widget_queue_resize (GTK_WIDGET (socket)); + if (widget_was_visible && gtk_widget_get_visible (GTK_WIDGET (socket_))) + gtk_widget_queue_resize (GTK_WIDGET (socket_)); - g_object_unref (socket); + g_object_unref (socket_); } +/** + * gtk_plug_construct: + * @plug: a #GtkPlug. + * @socket_id: the XID of the socket's window. + * + * Finish the initialization of @plug for a given #GtkSocket identified by + * @socket_id. This function will generally only be used by classes deriving from #GtkPlug. + **/ void gtk_plug_construct (GtkPlug *plug, GdkNativeWindow socket_id) +{ + gtk_plug_construct_for_display (plug, gdk_display_get_default (), socket_id); +} + +/** + * gtk_plug_construct_for_display: + * @plug: a #GtkPlug. + * @display: the #GdkDisplay associated with @socket_id's + * #GtkSocket. + * @socket_id: the XID of the socket's window. + * + * Finish the initialization of @plug for a given #GtkSocket identified by + * @socket_id which is currently displayed on @display. + * This function will generally only be used by classes deriving from #GtkPlug. + * + * Since: 2.2 + **/ +void +gtk_plug_construct_for_display (GtkPlug *plug, + GdkDisplay *display, + GdkNativeWindow socket_id) { if (socket_id) { gpointer user_data = NULL; - plug->socket_window = gdk_window_lookup (socket_id); - + plug->socket_window = gdk_window_lookup_for_display (display, socket_id); 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) { - if (GTK_IS_SOCKET (user_data)) - _gtk_plug_add_to_socket (plug, user_data); - else + gdk_window_get_user_data (plug->socket_window, &user_data); + + if (user_data) { - g_warning (G_STRLOC "Can't create GtkPlug as child of non-GtkSocket"); - plug->socket_window = NULL; + 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; + } } + else + g_object_ref (plug->socket_window); } + else + plug->socket_window = gdk_window_foreign_new_for_display (display, socket_id); - if (plug->socket_window) - g_signal_emit (G_OBJECT (plug), plug_signals[EMBEDDED], 0); + if (plug->socket_window) { + g_signal_emit (plug, plug_signals[EMBEDDED], 0); + + g_object_notify (G_OBJECT (plug), "embedded"); + } } } +/** + * gtk_plug_new: + * @socket_id: the window ID of the socket, or 0. + * + * Creates a new plug widget inside the #GtkSocket identified + * by @socket_id. If @socket_id is 0, the plug is left "unplugged" and + * can later be plugged into a #GtkSocket by gtk_socket_add_id(). + * + * Return value: the new #GtkPlug widget. + **/ GtkWidget* gtk_plug_new (GdkNativeWindow socket_id) { - GtkPlug *plug; - - plug = GTK_PLUG (gtk_type_new (GTK_TYPE_PLUG)); - gtk_plug_construct (plug, socket_id); - return GTK_WIDGET (plug); + return gtk_plug_new_for_display (gdk_display_get_default (), socket_id); } /** - * gtk_plug_get_id: - * @plug: a #GtkPlug. + * gtk_plug_new_for_display: + * @display : the #GdkDisplay on which @socket_id is displayed + * @socket_id: the XID of the socket's window. * - * Gets the window ID of a #GtkPlug widget, which can then - * be used to embed this window inside another window, for - * instance with gtk_socket_add_id(). - * - * Return value: the window ID for the plug - **/ -GdkNativeWindow -gtk_plug_get_id (GtkPlug *plug) + * Create a new plug widget inside the #GtkSocket identified by socket_id. + * + * Return value: the new #GtkPlug widget. + * + * Since: 2.2 + */ +GtkWidget* +gtk_plug_new_for_display (GdkDisplay *display, + GdkNativeWindow socket_id) { - g_return_val_if_fail (GTK_IS_PLUG (plug), 0); - - if (!GTK_WIDGET_REALIZED (plug)) - gtk_widget_realize (GTK_WIDGET (plug)); + GtkPlug *plug; - return GDK_WINDOW_XWINDOW (GTK_WIDGET (plug)->window); + plug = g_object_new (GTK_TYPE_PLUG, NULL); + gtk_plug_construct_for_display (plug, display, socket_id); + return GTK_WIDGET (plug); } static void -gtk_plug_unrealize (GtkWidget *widget) +gtk_plug_finalize (GObject *object) { - GtkPlug *plug; + GtkPlug *plug = GTK_PLUG (object); - g_return_if_fail (GTK_IS_PLUG (widget)); + if (plug->grabbed_keys) + { + g_hash_table_destroy (plug->grabbed_keys); + plug->grabbed_keys = NULL; + } + + G_OBJECT_CLASS (gtk_plug_parent_class)->finalize (object); +} - plug = GTK_PLUG (widget); +static void +gtk_plug_unrealize (GtkWidget *widget) +{ + GtkPlug *plug = GTK_PLUG (widget); if (plug->socket_window != NULL) { gdk_window_set_user_data (plug->socket_window, NULL); - gdk_window_unref (plug->socket_window); + g_object_unref (plug->socket_window); plug->socket_window = NULL; + + g_object_notify (G_OBJECT (widget), "embedded"); } if (!plug->same_app) { if (plug->modality_window) - handle_modality_off (plug); + _gtk_plug_handle_modality_off (plug); 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); + + GTK_WIDGET_CLASS (gtk_plug_parent_class)->unrealize (widget); } static void gtk_plug_realize (GtkWidget *widget) { - GtkWindow *window; - GtkPlug *plug; + GtkWindow *window = GTK_WINDOW (widget); + GtkPlug *plug = GTK_PLUG (widget); GdkWindowAttr attributes; gint attributes_mask; - g_return_if_fail (GTK_IS_PLUG (widget)); - - GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); - window = GTK_WINDOW (widget); - plug = GTK_PLUG (widget); + gtk_widget_set_realized (widget, TRUE); attributes.window_type = GDK_WINDOW_CHILD; /* XXX GDK_WINDOW_PLUG ? */ attributes.title = window->title; @@ -425,51 +625,61 @@ gtk_plug_realize (GtkWidget *widget) GDK_KEY_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | - GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK); attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP; attributes_mask |= (window->title ? GDK_WA_TITLE : 0); attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0); - if (GTK_WIDGET_TOPLEVEL (widget)) + if (gtk_widget_is_toplevel (widget)) { attributes.window_type = GDK_WINDOW_TOPLEVEL; gdk_error_trap_push (); - widget->window = gdk_window_new (plug->socket_window, - &attributes, attributes_mask); - gdk_flush (); + if (plug->socket_window) + widget->window = gdk_window_new (plug->socket_window, + &attributes, attributes_mask); + else /* If it's a passive plug, we use the root window */ + widget->window = gdk_window_new (gtk_widget_get_root_window (widget), + &attributes, attributes_mask); + + gdk_display_sync (gtk_widget_get_display (widget)); 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); + widget->window = gdk_window_new (gtk_widget_get_root_window (widget), + &attributes, attributes_mask); } - gdk_window_add_filter (widget->window, gtk_plug_filter_func, widget); + gdk_window_add_filter (widget->window, + _gtk_plug_windowing_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); + _gtk_plug_windowing_realize_toplevel (plug); } else - widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); 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); + + gdk_window_enable_synchronized_configure (widget->window); } static void gtk_plug_show (GtkWidget *widget) { - if (GTK_WIDGET_TOPLEVEL (widget)) - GTK_WIDGET_CLASS (parent_class)->show (widget); + if (gtk_widget_is_toplevel (widget)) + GTK_WIDGET_CLASS (gtk_plug_parent_class)->show (widget); else GTK_WIDGET_CLASS (bin_class)->show (widget); } @@ -477,8 +687,8 @@ gtk_plug_show (GtkWidget *widget) static void gtk_plug_hide (GtkWidget *widget) { - if (GTK_WIDGET_TOPLEVEL (widget)) - GTK_WIDGET_CLASS (parent_class)->hide (widget); + if (gtk_widget_is_toplevel (widget)) + GTK_WIDGET_CLASS (gtk_plug_parent_class)->hide (widget); else GTK_WIDGET_CLASS (bin_class)->hide (widget); } @@ -491,18 +701,20 @@ void gdk_synthesize_window_state (GdkWindow *window, static void gtk_plug_map (GtkWidget *widget) { - if (GTK_WIDGET_TOPLEVEL (widget)) + if (gtk_widget_is_toplevel (widget)) { GtkBin *bin = GTK_BIN (widget); + GtkPlug *plug = GTK_PLUG (widget); + GtkWidget *child; - GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); + gtk_widget_set_mapped (widget, TRUE); - if (bin->child && - GTK_WIDGET_VISIBLE (bin->child) && - !GTK_WIDGET_MAPPED (bin->child)) - gtk_widget_map (bin->child); + child = gtk_bin_get_child (bin); + if (gtk_widget_get_visible (child) && + !gtk_widget_get_mapped (child)) + gtk_widget_map (child); - xembed_set_info (widget->window, XEMBED_MAPPED); + _gtk_plug_windowing_map_toplevel (plug); gdk_synthesize_window_state (widget->window, GDK_WINDOW_STATE_WITHDRAWN, @@ -515,12 +727,15 @@ gtk_plug_map (GtkWidget *widget) static void gtk_plug_unmap (GtkWidget *widget) { - if (GTK_WIDGET_TOPLEVEL (widget)) + if (gtk_widget_is_toplevel (widget)) { - GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); + GtkPlug *plug = GTK_PLUG (widget); + + gtk_widget_set_mapped (widget, FALSE); gdk_window_hide (widget->window); - xembed_set_info (widget->window, 0); + + _gtk_plug_windowing_unmap_toplevel (plug); gdk_synthesize_window_state (widget->window, 0, @@ -534,30 +749,33 @@ static void gtk_plug_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { - if (GTK_WIDGET_TOPLEVEL (widget)) - GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation); + GtkWidget *child; + + if (gtk_widget_is_toplevel (widget)) + GTK_WIDGET_CLASS (gtk_plug_parent_class)->size_allocate (widget, allocation); else { GtkBin *bin = GTK_BIN (widget); widget->allocation = *allocation; - if (GTK_WIDGET_REALIZED (widget)) + if (gtk_widget_get_realized (widget)) gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height); - if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + child = gtk_bin_get_child (bin); + if (gtk_widget_get_visible (child)) { GtkAllocation child_allocation; - child_allocation.x = child_allocation.y = GTK_CONTAINER (widget)->border_width; + child_allocation.x = child_allocation.y = gtk_container_get_border_width (GTK_CONTAINER (widget)); 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); + gtk_widget_size_allocate (child, &child_allocation); } } @@ -567,47 +785,21 @@ static gboolean gtk_plug_key_press_event (GtkWidget *widget, GdkEventKey *event) { - if (GTK_WIDGET_TOPLEVEL (widget)) - { - if (!GTK_WINDOW (widget)->has_focus) - { - gtk_plug_forward_key_press (GTK_PLUG (widget), event); - return TRUE; - } - else - return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event); - } + if (gtk_widget_is_toplevel (widget)) + return GTK_WIDGET_CLASS (gtk_plug_parent_class)->key_press_event (widget, event); else return FALSE; } -static void -gtk_plug_forward_key_press (GtkPlug *plug, GdkEventKey *event) +static gboolean +gtk_plug_focus_event (GtkWidget *widget, + GdkEventFocus *event) { - XEvent xevent; - - xevent.xkey.type = KeyPress; - xevent.xkey.display = GDK_WINDOW_XDISPLAY (GTK_WIDGET(plug)->window); - xevent.xkey.window = GDK_WINDOW_XWINDOW (plug->socket_window); - xevent.xkey.root = GDK_ROOT_WINDOW (); /* FIXME */ - xevent.xkey.time = event->time; - /* FIXME, the following might cause big problems for - * non-GTK apps */ - xevent.xkey.x = 0; - xevent.xkey.y = 0; - xevent.xkey.x_root = 0; - xevent.xkey.y_root = 0; - xevent.xkey.state = event->state; - xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), - event->keyval); - xevent.xkey.same_screen = TRUE; /* FIXME ? */ - - gdk_error_trap_push (); - XSendEvent (GDK_DISPLAY (), - GDK_WINDOW_XWINDOW (plug->socket_window), - False, NoEventMask, &xevent); - gdk_flush (); - gdk_error_trap_pop (); + /* We eat focus-in events and focus-out events, since they + * can be generated by something like a keyboard grab on + * a child of the plug. + */ + return FALSE; } static void @@ -616,43 +808,15 @@ gtk_plug_set_focus (GtkWindow *window, { GtkPlug *plug = GTK_PLUG (window); - GTK_WINDOW_CLASS (parent_class)->set_focus (window, focus); + GTK_WINDOW_CLASS (gtk_plug_parent_class)->set_focus (window, focus); /* Ask for focus from embedder */ - if (focus && !window->has_focus) - { -#if 0 - XEvent xevent; - - xevent.xfocus.type = FocusIn; - xevent.xfocus.display = GDK_WINDOW_XDISPLAY (GTK_WIDGET(plug)->window); - xevent.xfocus.window = GDK_WINDOW_XWINDOW (plug->socket_window); - xevent.xfocus.mode = EMBEDDED_APP_WANTS_FOCUS; - xevent.xfocus.detail = FALSE; /* Don't force */ - - gdk_error_trap_push (); - XSendEvent (GDK_DISPLAY (), - GDK_WINDOW_XWINDOW (plug->socket_window), - False, NoEventMask, &xevent); - gdk_flush (); - gdk_error_trap_pop (); -#endif - - send_xembed_message (plug, XEMBED_REQUEST_FOCUS, 0, 0, 0, - gtk_get_current_event_time ()); - } + if (focus && !window->has_toplevel_focus) + _gtk_plug_windowing_set_focus (plug); } -#if 0 - -typedef struct -{ - guint accelerator_key; - GdkModifierType accelerator_mods; -} GrabbedKey; - static guint grabbed_key_hash (gconstpointer a) { @@ -677,7 +841,7 @@ grabbed_key_equal (gconstpointer a, gconstpointer b) } static void -add_grabbed_keys (gpointer key, gpointer val, gpointer data) +add_grabbed_key (gpointer key, gpointer val, gpointer data) { GrabbedKey *grabbed_key = key; GtkPlug *plug = data; @@ -685,14 +849,42 @@ add_grabbed_keys (gpointer key, gpointer val, gpointer data) if (!plug->grabbed_keys || !g_hash_table_lookup (plug->grabbed_keys, grabbed_key)) { - send_xembed_message (plug, XEMBED_GRAB_KEY, 0, - grabbed_key->accelerator_key, grabbed_key->accelerator_mods, - gtk_get_current_event_time ()); + _gtk_plug_windowing_add_grabbed_key (plug, + grabbed_key->accelerator_key, + grabbed_key->accelerator_mods); } } static void -remove_grabbed_keys (gpointer key, gpointer val, gpointer data) +add_grabbed_key_always (gpointer key, + gpointer val, + gpointer data) +{ + GrabbedKey *grabbed_key = key; + GtkPlug *plug = data; + + _gtk_plug_windowing_add_grabbed_key (plug, + grabbed_key->accelerator_key, + grabbed_key->accelerator_mods); +} + +/** + * _gtk_plug_add_all_grabbed_keys: + * + * @plug: a #GtkPlug + * + * Calls _gtk_plug_windowing_add_grabbed_key() on all the grabbed keys + * in the @plug. + */ +void +_gtk_plug_add_all_grabbed_keys (GtkPlug *plug) +{ + if (plug->grabbed_keys) + g_hash_table_foreach (plug->grabbed_keys, add_grabbed_key_always, plug); +} + +static void +remove_grabbed_key (gpointer key, gpointer val, gpointer data) { GrabbedKey *grabbed_key = key; GtkPlug *plug = data; @@ -700,74 +892,56 @@ remove_grabbed_keys (gpointer key, gpointer val, gpointer data) if (!plug->grabbed_keys || !g_hash_table_lookup (plug->grabbed_keys, grabbed_key)) { - send_xembed_message (plug, XEMBED_UNGRAB_KEY, 0, - grabbed_key->accelerator_key, grabbed_key->accelerator_mods, - gtk_get_current_event_time ()); + _gtk_plug_windowing_remove_grabbed_key (plug, + grabbed_key->accelerator_key, + grabbed_key->accelerator_mods); } } static void -gtk_plug_free_grabbed_keys (GHashTable *key_table) +keys_foreach (GtkWindow *window, + guint keyval, + GdkModifierType modifiers, + gboolean is_mnemonic, + gpointer data) { - g_hash_table_foreach (key_table, (GHFunc)g_free, NULL); - g_hash_table_destroy (key_table); + GHashTable *new_grabbed_keys = data; + GrabbedKey *key = g_slice_new (GrabbedKey); + + key->accelerator_key = keyval; + key->accelerator_mods = modifiers; + + g_hash_table_replace (new_grabbed_keys, key, key); } static void -gtk_plug_accel_entries_changed (GtkWindow *window) +grabbed_key_free (gpointer data) +{ + g_slice_free (GrabbedKey, data); +} + +static void +gtk_plug_keys_changed (GtkWindow *window) { GHashTable *new_grabbed_keys, *old_grabbed_keys; - GSList *accel_groups, *tmp_list; GtkPlug *plug = GTK_PLUG (window); - new_grabbed_keys = g_hash_table_new (grabbed_key_hash, grabbed_key_equal); + new_grabbed_keys = g_hash_table_new_full (grabbed_key_hash, grabbed_key_equal, (GDestroyNotify)grabbed_key_free, NULL); + _gtk_window_keys_foreach (window, keys_foreach, new_grabbed_keys); - accel_groups = gtk_accel_groups_from_object (G_OBJECT (window)); - - tmp_list = accel_groups; - - while (tmp_list) - { - GtkAccelGroup *accel_group = tmp_list->data; - gint i, n_entries; - GtkAccelEntry *entries; - - gtk_accel_group_get_entries (accel_group, &entries, &n_entries); - - for (i = 0; i < n_entries; i++) - { - GdkKeymapKey *keys; - gint n_keys; - - if (gdk_keymap_get_entries_for_keyval (NULL, entries[i].accelerator_key, &keys, &n_keys)) - { - GrabbedKey *key = g_new (GrabbedKey, 1); - - key->accelerator_key = keys[0].keycode; - key->accelerator_mods = entries[i].accelerator_mods; - - g_hash_table_insert (new_grabbed_keys, key, key); - - g_free (keys); - } - } - - tmp_list = tmp_list->next; - } - - g_hash_table_foreach (new_grabbed_keys, add_grabbed_keys, plug); + if (plug->socket_window) + g_hash_table_foreach (new_grabbed_keys, add_grabbed_key, plug); old_grabbed_keys = plug->grabbed_keys; plug->grabbed_keys = new_grabbed_keys; if (old_grabbed_keys) { - g_hash_table_foreach (old_grabbed_keys, remove_grabbed_keys, plug); - gtk_plug_free_grabbed_keys (old_grabbed_keys); + if (plug->socket_window) + g_hash_table_foreach (old_grabbed_keys, remove_grabbed_key, plug); + g_hash_table_destroy (old_grabbed_keys); } - } -#endif static gboolean gtk_plug_focus (GtkWidget *widget, @@ -777,9 +951,11 @@ gtk_plug_focus (GtkWidget *widget, GtkPlug *plug = GTK_PLUG (widget); GtkWindow *window = GTK_WINDOW (widget); GtkContainer *container = GTK_CONTAINER (widget); - GtkWidget *old_focus_child = container->focus_child; + GtkWidget *child; + GtkWidget *old_focus_child; GtkWidget *parent; - + + old_focus_child = gtk_container_get_focus_child (container); /* We override GtkWindow's behavior, since we don't want wrapping here. */ if (old_focus_child) @@ -798,131 +974,63 @@ gtk_plug_focus (GtkWidget *widget, } gtk_window_set_focus (GTK_WINDOW (container), NULL); - - if (!GTK_CONTAINER (window)->focus_child) - { - gint message = -1; - - switch (direction) - { - case GTK_DIR_UP: - case GTK_DIR_LEFT: - case GTK_DIR_TAB_BACKWARD: - message = XEMBED_FOCUS_PREV; - break; - case GTK_DIR_DOWN: - case GTK_DIR_RIGHT: - case GTK_DIR_TAB_FORWARD: - message = XEMBED_FOCUS_NEXT; - break; - } - - send_xembed_message (plug, message, 0, 0, 0, - gtk_get_current_event_time ()); - -#if 0 - gtk_window_set_focus (GTK_WINDOW (widget), NULL); - - gdk_error_trap_push (); - XSetInputFocus (GDK_DISPLAY (), - GDK_WINDOW_XWINDOW (plug->socket_window), - RevertToParent, event->time); - gdk_flush (); - gdk_error_trap_pop (); - - gtk_plug_forward_key_press (plug, event); -#endif - } } - - return FALSE; } else { /* Try to focus the first widget in the window */ - - if (gtk_widget_child_focus (bin->child, direction)) + child = gtk_bin_get_child (bin); + if (child && gtk_widget_child_focus (child, direction)) return TRUE; } + if (!gtk_container_get_focus_child (GTK_CONTAINER (window))) + _gtk_plug_windowing_focus_to_parent (plug, direction); + return FALSE; } static void gtk_plug_check_resize (GtkContainer *container) { - if (GTK_WIDGET_TOPLEVEL (container)) - GTK_CONTAINER_CLASS (parent_class)->check_resize (container); + if (gtk_widget_is_toplevel (GTK_WIDGET (container))) + GTK_CONTAINER_CLASS (gtk_plug_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, - glong data1, - glong data2, - guint32 time) -{ - if (plug->socket_window) - { - XEvent xevent; - - xevent.xclient.window = GDK_WINDOW_XWINDOW (plug->socket_window); - xevent.xclient.type = ClientMessage; - xevent.xclient.message_type = gdk_x11_get_xatom_by_name ("_XEMBED"); - xevent.xclient.format = 32; - xevent.xclient.data.l[0] = time; - xevent.xclient.data.l[1] = message; - xevent.xclient.data.l[2] = detail; - xevent.xclient.data.l[3] = data1; - xevent.xclient.data.l[4] = data2; - - gdk_error_trap_push (); - XSendEvent (GDK_DISPLAY (), - GDK_WINDOW_XWINDOW (plug->socket_window), - False, NoEventMask, &xevent); - gdk_flush (); - gdk_error_trap_pop (); - } -} - -static void -focus_first_last (GtkPlug *plug, - GtkDirectionType direction) -{ - GtkWindow *window = GTK_WINDOW (plug); - GtkWidget *parent; - - if (window->focus_widget) - { - parent = window->focus_widget->parent; - while (parent) - { - gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL); - parent = GTK_WIDGET (parent)->parent; - } - - gtk_window_set_focus (GTK_WINDOW (plug), NULL); - } - - gtk_widget_child_focus (GTK_WIDGET (plug), direction); -} - -static void -handle_modality_on (GtkPlug *plug) +/** + * _gtk_plug_handle_modality_on: + * + * @plug: a #GtkPlug + * + * Called from the GtkPlug backend when the corresponding socket has + * told the plug that it modality has toggled on. + */ +void +_gtk_plug_handle_modality_on (GtkPlug *plug) { if (!plug->modality_window) { plug->modality_window = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_screen (GTK_WINDOW (plug->modality_window), + gtk_widget_get_screen (GTK_WIDGET (plug))); + gtk_widget_realize (plug->modality_window); gtk_window_group_add_window (plug->modality_group, GTK_WINDOW (plug->modality_window)); gtk_grab_add (plug->modality_window); } } -static void -handle_modality_off (GtkPlug *plug) +/** + * _gtk_plug_handle_modality_off: + * + * @plug: a #GtkPlug + * + * Called from the GtkPlug backend when the corresponding socket has + * told the plug that it modality has toggled off. + */ +void +_gtk_plug_handle_modality_off (GtkPlug *plug) { if (plug->modality_window) { @@ -931,222 +1039,33 @@ handle_modality_off (GtkPlug *plug) } } -static void -xembed_set_info (GdkWindow *gdk_window, - unsigned long flags) +/** + * _gtk_plug_focus_first_last: + * + * @plug: a #GtkPlug + * @direction: a direction + * + * Called from the GtkPlug backend when the corresponding socket has + * told the plug that it has received the focus. + */ +void +_gtk_plug_focus_first_last (GtkPlug *plug, + GtkDirectionType direction) { - Display *display = GDK_WINDOW_XDISPLAY (gdk_window); - Window window = GDK_WINDOW_XWINDOW (gdk_window); - unsigned long buffer[2]; - - Atom xembed_info_atom = gdk_x11_get_xatom_by_name ("_XEMBED_INFO"); - - buffer[1] = 0; /* Protocol version */ - buffer[1] = flags; - - XChangeProperty (display, window, - xembed_info_atom, xembed_info_atom, 32, - PropModeReplace, - (unsigned char *)buffer, 2); -} + GtkWindow *window = GTK_WINDOW (plug); + GtkWidget *parent; -static void -handle_xembed_message (GtkPlug *plug, - glong message, - glong detail, - glong data1, - glong data2, - guint32 time) -{ - GTK_NOTE (PLUGSOCKET, - g_message ("Message of type %ld received", message)); - - switch (message) + if (window->focus_widget) { - case XEMBED_EMBEDDED_NOTIFY: - break; - case XEMBED_WINDOW_ACTIVATE: - GTK_NOTE(PLUGSOCKET, - g_message ("GtkPlug: ACTIVATE received")); - break; - case XEMBED_WINDOW_DEACTIVATE: - GTK_NOTE(PLUGSOCKET, - g_message ("GtkPlug: DEACTIVATE received")); - break; - - case XEMBED_MODALITY_ON: - handle_modality_on (plug); - break; - case XEMBED_MODALITY_OFF: - handle_modality_off (plug); - break; - - case XEMBED_FOCUS_IN: - switch (detail) + parent = window->focus_widget->parent; + while (parent) { - case XEMBED_FOCUS_FIRST: - focus_first_last (plug, GTK_DIR_TAB_FORWARD); - break; - case XEMBED_FOCUS_LAST: - focus_first_last (plug, GTK_DIR_TAB_BACKWARD); - break; - case XEMBED_FOCUS_CURRENT: - /* fall through */; + gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL); + parent = GTK_WIDGET (parent)->parent; } - case XEMBED_FOCUS_OUT: - { - GdkEvent event; - - event.focus_change.type = GDK_FOCUS_CHANGE; - event.focus_change.window = GTK_WIDGET (plug)->window; - event.focus_change.send_event = TRUE; - event.focus_change.in = (message == XEMBED_FOCUS_IN); - - gtk_widget_event (GTK_WIDGET (plug), &event); - - break; - } - - case XEMBED_REQUEST_FOCUS: - case XEMBED_FOCUS_NEXT: - case XEMBED_FOCUS_PREV: - case XEMBED_GRAB_KEY: - case XEMBED_UNGRAB_KEY: - g_warning ("GtkPlug: Invalid _XEMBED message of type %ld received", message); - break; - - default: - GTK_NOTE(PLUGSOCKET, - g_message ("GtkPlug: Ignoring unknown _XEMBED message of type %ld", message)); - break; - } -} - -static GdkFilterReturn -gtk_plug_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) -{ - GtkPlug *plug = GTK_PLUG (data); - XEvent *xevent = (XEvent *)gdk_xevent; - - GdkFilterReturn return_val; - - return_val = GDK_FILTER_CONTINUE; - - switch (xevent->type) - { - case ClientMessage: - if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name ("_XEMBED")) - { - handle_xembed_message (plug, - 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 GDK_FILTER_REMOVE; - } - else if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name ("WM_DELETE_WINDOW")) - { - /* We filter these out because we take being reparented back to the - * root window as the reliable end of the embedding protocol - */ - - return GDK_FILTER_REMOVE; - } - break; - case ReparentNotify: - { - XReparentEvent *xre = &xevent->xreparent; - gboolean was_embedded = plug->socket_window != NULL; - - return_val = GDK_FILTER_REMOVE; - - g_object_ref (plug); - - if (was_embedded) - { - /* End of embedding protocol for previous socket */ - - /* FIXME: race if we remove from another socket and - * then add to a local window before we get notification - * Probably need check in _gtk_plug_add_to_socket - */ - - if (xre->parent != GDK_WINDOW_XWINDOW (plug->socket_window)) - { - GtkWidget *widget = GTK_WIDGET (plug); - - gdk_window_set_user_data (plug->socket_window, NULL); - gdk_window_unref (plug->socket_window); - plug->socket_window = NULL; - - /* Emit a delete window, as if the user attempted - * to close the toplevel. Simple as to how we - * handle WM_DELETE_WINDOW, if it isn't handled - * we destroy the widget. BUt only do this if - * we are being reparented to the root window. - * Moving from one embedder to another should - * be invisible to the app. - */ - - if (xre->parent == GDK_ROOT_WINDOW()) - { - GdkEvent event; - - event.any.type = GDK_DELETE; - event.any.window = g_object_ref (widget->window); - event.any.send_event = FALSE; - - if (!gtk_widget_event (widget, &event)) - gtk_widget_destroy (widget); - - g_object_unref (event.any.window); - } - } - else - break; - } - - if (xre->parent != GDK_ROOT_WINDOW ()) - { - /* Start of embedding protocol */ - - plug->socket_window = gdk_window_lookup (xre->parent); - if (plug->socket_window) - { - gpointer user_data = NULL; - gdk_window_get_user_data (plug->socket_window, &user_data); - - if (user_data) - { - g_warning (G_STRLOC "Plug reparented unexpectedly into window in the same process"); - plug->socket_window = NULL; - break; - } - - g_object_ref (plug->socket_window); - } - else - { - plug->socket_window = gdk_window_foreign_new (xre->parent); - if (!plug->socket_window) /* Already gone */ - break; - } - - /* FIXME: Add grabbed keys here */ - - if (!was_embedded) - g_signal_emit (G_OBJECT (plug), plug_signals[EMBEDDED], 0); - } - - g_object_unref (plug); - - break; - } + gtk_window_set_focus (GTK_WINDOW (plug), NULL); } - return GDK_FILTER_CONTINUE; + gtk_widget_child_focus (GTK_WIDGET (plug), direction); }