]> Pileus Git - ~andy/gtk/blob - gtk/gtkplug.c
Merge branch 'bgo593793-filechooser-recent-folders-master'
[~andy/gtk] / gtk / gtkplug.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 /* By Owen Taylor <otaylor@gtk.org>              98/4/4 */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
26  */
27
28 #include "config.h"
29
30 #include "gtkdebug.h"
31 #include "gtkmain.h"
32 #include "gtkmarshalers.h"
33 #include "gtkplug.h"
34 #include "gtkintl.h"
35 #include "gtkprivate.h"
36 #include "gtksocketprivate.h"
37 #include "gtkwidgetprivate.h"
38 #include "gtkwindowprivate.h"
39 #include "gtkxembed.h"
40
41 #include <gdk/gdkx.h>
42
43 /**
44  * SECTION:gtkplug
45  * @Short_description: Toplevel for embedding into other processes
46  * @Title: GtkPlug
47  * @include: gtk/gtkx.h
48  * @See_also: #GtkSocket
49  *
50  * Together with #GtkSocket, #GtkPlug provides the ability to embed
51  * widgets from one process into another process in a fashion that is
52  * transparent to the user. One process creates a #GtkSocket widget
53  * and passes the ID of that widget's window to the other process,
54  * which then creates a #GtkPlug with that window ID. Any widgets
55  * contained in the #GtkPlug then will appear inside the first
56  * application's window.
57  *
58  * The communication between a #GtkSocket and a #GtkPlug follows the
59  * <ulink url="http://www.freedesktop.org/Standards/xembed-spec">XEmbed</ulink>
60  * protocol. This protocol has also been implemented in other toolkits,
61  * e.g. <application>Qt</application>, allowing the same level of
62  * integration when embedding a <application>Qt</application> widget
63  * in GTK+ or vice versa.
64  *
65  * <note>
66  * The #GtkPlug and #GtkSocket widgets are only available when GTK+
67  * is compiled for the X11 platform and %GDK_WINDOWING_X11 is defined.
68  * They can only be used on a #GdkX11Display. To use #GtkPlug and
69  * #GtkSocket, you need to include the <filename>gtk/gtkx.h</filename>
70  * header.
71  * </note>
72  */
73
74 struct _GtkPlugPrivate
75 {
76   GtkWidget      *modality_window;
77   GtkWindowGroup *modality_group;
78
79   GdkWindow      *socket_window;
80
81   GHashTable     *grabbed_keys;
82
83   guint  same_app : 1;
84 };
85
86 static void            gtk_plug_get_property          (GObject     *object,
87                                                        guint        prop_id,
88                                                        GValue      *value,
89                                                        GParamSpec  *pspec);
90 static void            gtk_plug_finalize              (GObject          *object);
91 static void            gtk_plug_realize               (GtkWidget        *widget);
92 static void            gtk_plug_unrealize             (GtkWidget        *widget);
93 static void            gtk_plug_show                  (GtkWidget        *widget);
94 static void            gtk_plug_hide                  (GtkWidget        *widget);
95 static void            gtk_plug_map                   (GtkWidget        *widget);
96 static void            gtk_plug_unmap                 (GtkWidget        *widget);
97 static void            gtk_plug_size_allocate         (GtkWidget        *widget,
98                                                        GtkAllocation    *allocation);
99 static gboolean        gtk_plug_key_press_event       (GtkWidget        *widget,
100                                                        GdkEventKey      *event);
101 static gboolean        gtk_plug_focus_event           (GtkWidget        *widget,
102                                                        GdkEventFocus    *event);
103 static void            gtk_plug_set_focus             (GtkWindow        *window,
104                                                        GtkWidget        *focus);
105 static gboolean        gtk_plug_focus                 (GtkWidget        *widget,
106                                                        GtkDirectionType  direction);
107 static void            gtk_plug_check_resize          (GtkContainer     *container);
108 static void            gtk_plug_keys_changed          (GtkWindow        *window);
109
110 static void            xembed_set_info                (GdkWindow        *window,
111                                                        unsigned long     flags);
112
113 static GtkBinClass *bin_class = NULL;
114
115 typedef struct
116 {
117   guint                  accelerator_key;
118   GdkModifierType        accelerator_mods;
119 } GrabbedKey;
120
121 enum {
122   PROP_0,
123   PROP_EMBEDDED,
124   PROP_SOCKET_WINDOW
125 };
126
127 enum {
128   EMBEDDED,
129   LAST_SIGNAL
130 }; 
131
132 static guint plug_signals[LAST_SIGNAL] = { 0 };
133
134 G_DEFINE_TYPE (GtkPlug, gtk_plug, GTK_TYPE_WINDOW)
135
136 static void
137 gtk_plug_get_property (GObject    *object,
138                        guint       prop_id,
139                        GValue     *value,
140                        GParamSpec *pspec)
141 {
142   GtkPlug *plug = GTK_PLUG (object);
143   GtkPlugPrivate *priv = plug->priv;
144
145   switch (prop_id)
146     {
147     case PROP_EMBEDDED:
148       g_value_set_boolean (value, priv->socket_window != NULL);
149       break;
150     case PROP_SOCKET_WINDOW:
151       g_value_set_object (value, priv->socket_window);
152       break;
153     default:
154       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
155       break;
156     }
157 }
158
159 static void
160 gtk_plug_class_init (GtkPlugClass *class)
161 {
162   GObjectClass *gobject_class = (GObjectClass *)class;
163   GtkWidgetClass *widget_class = (GtkWidgetClass *)class;
164   GtkWindowClass *window_class = (GtkWindowClass *)class;
165   GtkContainerClass *container_class = (GtkContainerClass *)class;
166
167   bin_class = g_type_class_peek (GTK_TYPE_BIN);
168
169   gobject_class->get_property = gtk_plug_get_property;
170   gobject_class->finalize = gtk_plug_finalize;
171   
172   widget_class->realize = gtk_plug_realize;
173   widget_class->unrealize = gtk_plug_unrealize;
174   widget_class->key_press_event = gtk_plug_key_press_event;
175   widget_class->focus_in_event = gtk_plug_focus_event;
176   widget_class->focus_out_event = gtk_plug_focus_event;
177
178   widget_class->show = gtk_plug_show;
179   widget_class->hide = gtk_plug_hide;
180   widget_class->map = gtk_plug_map;
181   widget_class->unmap = gtk_plug_unmap;
182   widget_class->size_allocate = gtk_plug_size_allocate;
183
184   widget_class->focus = gtk_plug_focus;
185
186   gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_PANEL);
187
188   container_class->check_resize = gtk_plug_check_resize;
189
190   window_class->set_focus = gtk_plug_set_focus;
191   window_class->keys_changed = gtk_plug_keys_changed;
192
193   /**
194    * GtkPlug:embedded:
195    *
196    * %TRUE if the plug is embedded in a socket.
197    *
198    * Since: 2.12
199    */
200   g_object_class_install_property (gobject_class,
201                                    PROP_EMBEDDED,
202                                    g_param_spec_boolean ("embedded",
203                                                          P_("Embedded"),
204                                                          P_("Whether the plug is embedded"),
205                                                          FALSE,
206                                                          GTK_PARAM_READABLE));
207
208   /**
209    * GtkPlug:socket-window:
210    *
211    * The window of the socket the plug is embedded in.
212    *
213    * Since: 2.14
214    */
215   g_object_class_install_property (gobject_class,
216                                    PROP_SOCKET_WINDOW,
217                                    g_param_spec_object ("socket-window",
218                                                         P_("Socket Window"),
219                                                         P_("The window of the socket the plug is embedded in"),
220                                                         GDK_TYPE_WINDOW,
221                                                         GTK_PARAM_READABLE));
222
223   /**
224    * GtkPlug::embedded:
225    * @plug: the object on which the signal was emitted
226    *
227    * Gets emitted when the plug becomes embedded in a socket.
228    */ 
229   plug_signals[EMBEDDED] =
230     g_signal_new (I_("embedded"),
231                   G_OBJECT_CLASS_TYPE (class),
232                   G_SIGNAL_RUN_LAST,
233                   G_STRUCT_OFFSET (GtkPlugClass, embedded),
234                   NULL, NULL,
235                   _gtk_marshal_VOID__VOID,
236                   G_TYPE_NONE, 0);
237
238   g_type_class_add_private (class, sizeof (GtkPlugPrivate));
239 }
240
241 static void
242 gtk_plug_init (GtkPlug *plug)
243 {
244   plug->priv = G_TYPE_INSTANCE_GET_PRIVATE (plug,
245                                             GTK_TYPE_PLUG,
246                                             GtkPlugPrivate);
247 }
248
249 /**
250  * gtk_plug_handle_modality_on:
251  *
252  * @plug: a #GtkPlug
253  *
254  * Called from the GtkPlug backend when the corresponding socket has
255  * told the plug that it modality has toggled on.
256  */
257 static void
258 gtk_plug_handle_modality_on (GtkPlug *plug)
259 {
260   GtkPlugPrivate *priv = plug->priv;
261
262   if (!priv->modality_window)
263     {
264       priv->modality_window = gtk_window_new (GTK_WINDOW_POPUP);
265       gtk_window_set_screen (GTK_WINDOW (priv->modality_window),
266                              gtk_widget_get_screen (GTK_WIDGET (plug)));
267       gtk_widget_realize (priv->modality_window);
268       gtk_window_group_add_window (priv->modality_group, GTK_WINDOW (priv->modality_window));
269       gtk_grab_add (priv->modality_window);
270     }
271 }
272
273 /**
274  * gtk_plug_handle_modality_off:
275  *
276  * @plug: a #GtkPlug
277  *
278  * Called from the GtkPlug backend when the corresponding socket has
279  * told the plug that it modality has toggled off.
280  */
281 static void
282 gtk_plug_handle_modality_off (GtkPlug *plug)
283 {
284   GtkPlugPrivate *priv = plug->priv;
285
286   if (priv->modality_window)
287     {
288       gtk_widget_destroy (priv->modality_window);
289       priv->modality_window = NULL;
290     }
291 }
292
293 static void
294 gtk_plug_set_is_child (GtkPlug  *plug,
295                        gboolean  is_child)
296 {
297   GtkPlugPrivate *priv = plug->priv;
298   GtkWidget *widget = GTK_WIDGET (plug);
299
300   g_assert (!gtk_widget_get_parent (widget));
301
302   if (is_child)
303     {
304       if (priv->modality_window)
305         gtk_plug_handle_modality_off (plug);
306
307       if (priv->modality_group)
308         {
309           gtk_window_group_remove_window (priv->modality_group, GTK_WINDOW (plug));
310           g_object_unref (priv->modality_group);
311           priv->modality_group = NULL;
312         }
313       
314       /* As a toplevel, the MAPPED flag doesn't correspond
315        * to whether the widget->window is mapped; we unmap
316        * here, but don't bother remapping -- we will get mapped
317        * by gtk_widget_set_parent ().
318        */
319       if (gtk_widget_get_mapped (widget))
320         gtk_widget_unmap (widget);
321
322       _gtk_window_set_is_toplevel (GTK_WINDOW (plug), FALSE);
323       gtk_container_set_resize_mode (GTK_CONTAINER (plug), GTK_RESIZE_PARENT);
324
325       _gtk_widget_propagate_hierarchy_changed (widget, widget);
326     }
327   else
328     {
329       if (gtk_window_get_focus (GTK_WINDOW (plug)))
330         gtk_window_set_focus (GTK_WINDOW (plug), NULL);
331       if (gtk_window_get_default_widget (GTK_WINDOW (plug)))
332         gtk_window_set_default (GTK_WINDOW (plug), NULL);
333
334       priv->modality_group = gtk_window_group_new ();
335       gtk_window_group_add_window (priv->modality_group, GTK_WINDOW (plug));
336
337       _gtk_window_set_is_toplevel (GTK_WINDOW (plug), TRUE);
338       gtk_container_set_resize_mode (GTK_CONTAINER (plug), GTK_RESIZE_QUEUE);
339
340       _gtk_widget_propagate_hierarchy_changed (GTK_WIDGET (plug), NULL);
341     }
342 }
343
344 /**
345  * gtk_plug_get_id:
346  * @plug: a #GtkPlug.
347  * 
348  * Gets the window ID of a #GtkPlug widget, which can then
349  * be used to embed this window inside another window, for
350  * instance with gtk_socket_add_id().
351  * 
352  * Return value: the window ID for the plug
353  **/
354 Window
355 gtk_plug_get_id (GtkPlug *plug)
356 {
357   g_return_val_if_fail (GTK_IS_PLUG (plug), 0);
358
359   if (!gtk_widget_get_realized (GTK_WIDGET (plug)))
360     gtk_widget_realize (GTK_WIDGET (plug));
361
362   return GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (plug)));
363 }
364
365 /**
366  * gtk_plug_get_embedded:
367  * @plug: a #GtkPlug
368  *
369  * Determines whether the plug is embedded in a socket.
370  *
371  * Return value: %TRUE if the plug is embedded in a socket
372  *
373  * Since: 2.14
374  **/
375 gboolean
376 gtk_plug_get_embedded (GtkPlug *plug)
377 {
378   g_return_val_if_fail (GTK_IS_PLUG (plug), FALSE);
379
380   return plug->priv->socket_window != NULL;
381 }
382
383 /**
384  * gtk_plug_get_socket_window:
385  * @plug: a #GtkPlug
386  *
387  * Retrieves the socket the plug is embedded in.
388  *
389  * Return value: (transfer none): the window of the socket, or %NULL
390  *
391  * Since: 2.14
392  **/
393 GdkWindow *
394 gtk_plug_get_socket_window (GtkPlug *plug)
395 {
396   g_return_val_if_fail (GTK_IS_PLUG (plug), NULL);
397
398   return plug->priv->socket_window;
399 }
400
401 /**
402  * _gtk_plug_add_to_socket:
403  * @plug: a #GtkPlug
404  * @socket_: a #GtkSocket
405  * 
406  * Adds a plug to a socket within the same application.
407  **/
408 void
409 _gtk_plug_add_to_socket (GtkPlug   *plug,
410                          GtkSocket *socket_)
411 {
412   GtkPlugPrivate *priv;
413   GtkWidget *widget;
414   
415   g_return_if_fail (GTK_IS_PLUG (plug));
416   g_return_if_fail (GTK_IS_SOCKET (socket_));
417   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (socket_)));
418
419   priv = plug->priv;
420   widget = GTK_WIDGET (plug);
421
422   gtk_plug_set_is_child (plug, TRUE);
423   priv->same_app = TRUE;
424   socket_->priv->same_app = TRUE;
425   socket_->priv->plug_widget = widget;
426
427   priv->socket_window = gtk_widget_get_window (GTK_WIDGET (socket_));
428   g_object_ref (priv->socket_window);
429   g_signal_emit (plug, plug_signals[EMBEDDED], 0);
430   g_object_notify (G_OBJECT (plug), "embedded");
431
432   if (gtk_widget_get_realized (widget))
433     {
434       GdkWindow *window;
435
436       window = gtk_widget_get_window (widget);
437       gdk_window_reparent (window, priv->socket_window,
438                            -gdk_window_get_width (window),
439                            -gdk_window_get_height (window));
440     }
441
442   gtk_widget_set_parent (widget, GTK_WIDGET (socket_));
443
444   g_signal_emit_by_name (socket_, "plug-added");
445 }
446
447 /**
448  * _gtk_plug_send_delete_event:
449  * @widget: a #GtkWidget
450  *
451  * Send a GDK_DELETE event to the @widget and destroy it if
452  * necessary. Internal GTK function, called from this file or the
453  * backend-specific GtkPlug implementation.
454  */
455 void
456 _gtk_plug_send_delete_event (GtkWidget *widget)
457 {
458   GdkEvent *event = gdk_event_new (GDK_DELETE);
459
460   event->any.window = g_object_ref (gtk_widget_get_window (widget));
461   event->any.send_event = FALSE;
462
463   g_object_ref (widget);
464
465   if (!gtk_widget_event (widget, event))
466     gtk_widget_destroy (widget);
467
468   g_object_unref (widget);
469
470   gdk_event_free (event);
471 }
472
473 /**
474  * _gtk_plug_remove_from_socket:
475  * @plug: a #GtkPlug
476  * @socket_: a #GtkSocket
477  * 
478  * Removes a plug from a socket within the same application.
479  **/
480 void
481 _gtk_plug_remove_from_socket (GtkPlug   *plug,
482                               GtkSocket *socket_)
483 {
484   GtkPlugPrivate *priv;
485   GtkWidget *widget;
486   GdkWindow *window;
487   gboolean result;
488   gboolean widget_was_visible;
489
490   g_return_if_fail (GTK_IS_PLUG (plug));
491   g_return_if_fail (GTK_IS_SOCKET (socket_));
492   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (plug)));
493
494   priv = plug->priv;
495   widget = GTK_WIDGET (plug);
496
497   if (_gtk_widget_get_in_reparent (widget))
498     return;
499
500   g_object_ref (plug);
501   g_object_ref (socket_);
502
503   widget_was_visible = gtk_widget_get_visible (widget);
504   window = gtk_widget_get_window (widget);
505
506   gdk_window_hide (window);
507   _gtk_widget_set_in_reparent (widget, TRUE);
508   gdk_window_reparent (window,
509                        gtk_widget_get_root_window (widget),
510                        0, 0);
511   gtk_widget_unparent (GTK_WIDGET (plug));
512   _gtk_widget_set_in_reparent (widget, FALSE);
513   
514   socket_->priv->plug_widget = NULL;
515   if (socket_->priv->plug_window != NULL)
516     {
517       g_object_unref (socket_->priv->plug_window);
518       socket_->priv->plug_window = NULL;
519     }
520   
521   socket_->priv->same_app = FALSE;
522
523   priv->same_app = FALSE;
524   if (priv->socket_window != NULL)
525     {
526       g_object_unref (priv->socket_window);
527       priv->socket_window = NULL;
528     }
529   gtk_plug_set_is_child (plug, FALSE);
530
531   g_signal_emit_by_name (socket_, "plug-removed", &result);
532   if (!result)
533     gtk_widget_destroy (GTK_WIDGET (socket_));
534
535   if (window)
536     _gtk_plug_send_delete_event (widget);
537
538   g_object_unref (plug);
539
540   if (widget_was_visible && gtk_widget_get_visible (GTK_WIDGET (socket_)))
541     gtk_widget_queue_resize (GTK_WIDGET (socket_));
542
543   g_object_unref (socket_);
544 }
545
546 /**
547  * gtk_plug_construct:
548  * @plug: a #GtkPlug.
549  * @socket_id: the XID of the socket's window.
550  *
551  * Finish the initialization of @plug for a given #GtkSocket identified by
552  * @socket_id. This function will generally only be used by classes deriving from #GtkPlug.
553  **/
554 void
555 gtk_plug_construct (GtkPlug *plug,
556                     Window   socket_id)
557 {
558   gtk_plug_construct_for_display (plug, gdk_display_get_default (), socket_id);
559 }
560
561 /**
562  * gtk_plug_construct_for_display:
563  * @plug: a #GtkPlug.
564  * @display: the #GdkDisplay associated with @socket_id's 
565  *           #GtkSocket.
566  * @socket_id: the XID of the socket's window.
567  *
568  * Finish the initialization of @plug for a given #GtkSocket identified by
569  * @socket_id which is currently displayed on @display.
570  * This function will generally only be used by classes deriving from #GtkPlug.
571  *
572  * Since: 2.2
573  **/
574 void
575 gtk_plug_construct_for_display (GtkPlug    *plug,
576                                 GdkDisplay *display,
577                                 Window      socket_id)
578 {
579   GtkPlugPrivate *priv;
580
581   g_return_if_fail (GTK_IS_PLUG (plug));
582   g_return_if_fail (GDK_IS_DISPLAY (display));
583
584   priv = plug->priv;
585
586   if (socket_id)
587     {
588       gpointer user_data = NULL;
589
590       if (GDK_IS_X11_DISPLAY (display))
591         priv->socket_window = gdk_x11_window_lookup_for_display (display, socket_id);
592       else
593         priv->socket_window = NULL;
594
595       if (priv->socket_window)
596         {
597           gdk_window_get_user_data (priv->socket_window, &user_data);
598
599           if (user_data)
600             {
601               if (GTK_IS_SOCKET (user_data))
602                 _gtk_plug_add_to_socket (plug, user_data);
603               else
604                 {
605                   g_warning (G_STRLOC "Can't create GtkPlug as child of non-GtkSocket");
606                   priv->socket_window = NULL;
607                 }
608             }
609           else
610             g_object_ref (priv->socket_window);
611         }
612       else if (GDK_IS_X11_DISPLAY (display))
613         priv->socket_window = gdk_x11_window_foreign_new_for_display (display, socket_id);
614
615       if (priv->socket_window) {
616         g_signal_emit (plug, plug_signals[EMBEDDED], 0);
617
618         g_object_notify (G_OBJECT (plug), "embedded");
619       }
620     }
621 }
622
623 /**
624  * gtk_plug_new:
625  * @socket_id:  the window ID of the socket, or 0.
626  * 
627  * Creates a new plug widget inside the #GtkSocket identified
628  * by @socket_id. If @socket_id is 0, the plug is left "unplugged" and
629  * can later be plugged into a #GtkSocket by  gtk_socket_add_id().
630  * 
631  * Return value: the new #GtkPlug widget.
632  **/
633 GtkWidget*
634 gtk_plug_new (Window socket_id)
635 {
636   return gtk_plug_new_for_display (gdk_display_get_default (), socket_id);
637 }
638
639 /**
640  * gtk_plug_new_for_display:
641  * @display: the #GdkDisplay on which @socket_id is displayed
642  * @socket_id: the XID of the socket's window.
643  * 
644  * Create a new plug widget inside the #GtkSocket identified by socket_id.
645  *
646  * Return value: the new #GtkPlug widget.
647  *
648  * Since: 2.2
649  */
650 GtkWidget*
651 gtk_plug_new_for_display (GdkDisplay *display,
652                           Window      socket_id)
653 {
654   GtkPlug *plug;
655
656   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
657
658   plug = g_object_new (GTK_TYPE_PLUG, NULL);
659   gtk_plug_construct_for_display (plug, display, socket_id);
660   return GTK_WIDGET (plug);
661 }
662
663 static void
664 gtk_plug_finalize (GObject *object)
665 {
666   GtkPlug *plug = GTK_PLUG (object);
667   GtkPlugPrivate *priv = plug->priv;
668
669   if (priv->grabbed_keys)
670     g_hash_table_destroy (priv->grabbed_keys);
671
672   G_OBJECT_CLASS (gtk_plug_parent_class)->finalize (object);
673 }
674
675 static void
676 gtk_plug_unrealize (GtkWidget *widget)
677 {
678   GtkPlug *plug = GTK_PLUG (widget);
679   GtkPlugPrivate *priv = plug->priv;
680
681   if (priv->socket_window != NULL)
682     {
683       gdk_window_set_user_data (priv->socket_window, NULL);
684       g_object_unref (priv->socket_window);
685       priv->socket_window = NULL;
686
687       g_object_notify (G_OBJECT (widget), "embedded");
688     }
689
690   if (!priv->same_app)
691     {
692       if (priv->modality_window)
693         gtk_plug_handle_modality_off (plug);
694
695       gtk_window_group_remove_window (priv->modality_group, GTK_WINDOW (plug));
696       g_object_unref (priv->modality_group);
697     }
698
699   GTK_WIDGET_CLASS (gtk_plug_parent_class)->unrealize (widget);
700 }
701
702 static void
703 xembed_set_info (GdkWindow     *window,
704                  unsigned long  flags)
705 {
706   GdkDisplay *display = gdk_window_get_display (window);
707   unsigned long buffer[2];
708
709   Atom xembed_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO");
710
711   buffer[0] = GTK_XEMBED_PROTOCOL_VERSION;
712   buffer[1] = flags;
713
714   XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
715                    GDK_WINDOW_XID (window),
716                    xembed_info_atom, xembed_info_atom, 32,
717                    PropModeReplace,
718                    (unsigned char *)buffer, 2);
719 }
720
721 /**
722  * gtk_plug_focus_first_last:
723  *
724  * @plug: a #GtkPlug
725  * @direction: a direction
726  *
727  * Called from the GtkPlug backend when the corresponding socket has
728  * told the plug that it has received the focus.
729  */
730 static void
731 gtk_plug_focus_first_last (GtkPlug          *plug,
732                            GtkDirectionType  direction)
733 {
734   GtkWindow *window = GTK_WINDOW (plug);
735   GtkWidget *focus_widget;
736   GtkWidget *parent;
737
738   focus_widget = gtk_window_get_focus (window);
739   if (focus_widget)
740     {
741       parent = gtk_widget_get_parent (focus_widget);
742       while (parent)
743         {
744           gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
745           parent = gtk_widget_get_parent (parent);
746         }
747       
748       gtk_window_set_focus (GTK_WINDOW (plug), NULL);
749     }
750
751   gtk_widget_child_focus (GTK_WIDGET (plug), direction);
752 }
753
754 static void
755 handle_xembed_message (GtkPlug           *plug,
756                        XEmbedMessageType  message,
757                        glong              detail,
758                        glong              data1,
759                        glong              data2,
760                        guint32            time)
761 {
762   GtkWindow *window = GTK_WINDOW (plug);
763
764   GTK_NOTE (PLUGSOCKET,
765             g_message ("GtkPlug: %s received", _gtk_xembed_message_name (message)));
766   
767   switch (message)
768     {
769     case XEMBED_EMBEDDED_NOTIFY:
770       break;
771     case XEMBED_WINDOW_ACTIVATE:
772       _gtk_window_set_is_active (window, TRUE);
773       break;
774     case XEMBED_WINDOW_DEACTIVATE:
775       _gtk_window_set_is_active (window, FALSE);
776       break;
777       
778     case XEMBED_MODALITY_ON:
779       gtk_plug_handle_modality_on (plug);
780       break;
781     case XEMBED_MODALITY_OFF:
782       gtk_plug_handle_modality_off (plug);
783       break;
784
785     case XEMBED_FOCUS_IN:
786       _gtk_window_set_has_toplevel_focus (window, TRUE);
787       switch (detail)
788         {
789         case XEMBED_FOCUS_FIRST:
790           gtk_plug_focus_first_last (plug, GTK_DIR_TAB_FORWARD);
791           break;
792         case XEMBED_FOCUS_LAST:
793           gtk_plug_focus_first_last (plug, GTK_DIR_TAB_BACKWARD);
794           break;
795         case XEMBED_FOCUS_CURRENT:
796           break;
797         }
798       break;
799
800     case XEMBED_FOCUS_OUT:
801       _gtk_window_set_has_toplevel_focus (window, FALSE);
802       break;
803       
804     case XEMBED_GRAB_KEY:
805     case XEMBED_UNGRAB_KEY:
806     case XEMBED_GTK_GRAB_KEY:
807     case XEMBED_GTK_UNGRAB_KEY:
808     case XEMBED_REQUEST_FOCUS:
809     case XEMBED_FOCUS_NEXT:
810     case XEMBED_FOCUS_PREV:
811       g_warning ("GtkPlug: Invalid _XEMBED message %s received", _gtk_xembed_message_name (message));
812       break;
813       
814     default:
815       GTK_NOTE(PLUGSOCKET,
816                g_message ("GtkPlug: Ignoring unknown _XEMBED message of type %d", message));
817       break;
818     }
819 }
820 static GdkFilterReturn
821 gtk_plug_filter_func (GdkXEvent *gdk_xevent,
822                       GdkEvent  *event,
823                       gpointer   data)
824 {
825   GdkScreen *screen = gdk_window_get_screen (event->any.window);
826   GdkDisplay *display = gdk_screen_get_display (screen);
827   GtkPlug *plug = GTK_PLUG (data);
828   GtkPlugPrivate *priv = plug->priv;
829   XEvent *xevent = (XEvent *)gdk_xevent;
830   GHashTableIter iter;
831   gpointer key;
832   GdkFilterReturn return_val;
833
834   return_val = GDK_FILTER_CONTINUE;
835
836   switch (xevent->type)
837     {
838     case ClientMessage:
839       if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED"))
840         {
841           _gtk_xembed_push_message (xevent);
842           handle_xembed_message (plug,
843                                  xevent->xclient.data.l[1],
844                                  xevent->xclient.data.l[2],
845                                  xevent->xclient.data.l[3],
846                                  xevent->xclient.data.l[4],
847                                  xevent->xclient.data.l[0]);
848           _gtk_xembed_pop_message ();
849
850           return_val = GDK_FILTER_REMOVE;
851         }
852       else if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW"))
853         {
854           /* We filter these out because we take being reparented back to the
855            * root window as the reliable end of the embedding protocol
856            */
857
858           return_val = GDK_FILTER_REMOVE;
859         }
860       break;
861     case ReparentNotify:
862       {
863         XReparentEvent *xre = &xevent->xreparent;
864         gboolean was_embedded = priv->socket_window != NULL;
865
866         GTK_NOTE (PLUGSOCKET, g_message("GtkPlug: ReparentNotify received"));
867
868         return_val = GDK_FILTER_REMOVE;
869         
870         g_object_ref (plug);
871         
872         if (was_embedded)
873           {
874             /* End of embedding protocol for previous socket */
875             
876             GTK_NOTE (PLUGSOCKET, g_message ("GtkPlug: end of embedding"));
877             /* FIXME: race if we remove from another socket and
878              * then add to a local window before we get notification
879              * Probably need check in _gtk_plug_add_to_socket
880              */
881
882             if (xre->parent != GDK_WINDOW_XID (priv->socket_window))
883               {
884                 GtkWidget *widget = GTK_WIDGET (plug);
885
886                 gdk_window_set_user_data (priv->socket_window, NULL);
887                 g_object_unref (priv->socket_window);
888                 priv->socket_window = NULL;
889
890                 /* Emit a delete window, as if the user attempted
891                  * to close the toplevel. Simple as to how we
892                  * handle WM_DELETE_WINDOW, if it isn't handled
893                  * we destroy the widget. BUt only do this if
894                  * we are being reparented to the root window.
895                  * Moving from one embedder to another should
896                  * be invisible to the app.
897                  */
898
899                 if (xre->parent == GDK_WINDOW_XID (gdk_screen_get_root_window (screen)))
900                   {
901                     GTK_NOTE (PLUGSOCKET, g_message ("GtkPlug: calling gtk_plug_send_delete_event()"));
902                     _gtk_plug_send_delete_event (widget);
903
904                     g_object_notify (G_OBJECT (plug), "embedded");
905                   }
906               }
907             else
908               goto done;
909           }
910
911         if (xre->parent != GDK_WINDOW_XID (gdk_screen_get_root_window (screen)))
912           {
913             /* Start of embedding protocol */
914
915             GTK_NOTE (PLUGSOCKET, g_message ("GtkPlug: start of embedding"));
916
917             priv->socket_window = gdk_x11_window_lookup_for_display (display, xre->parent);
918             if (priv->socket_window)
919               {
920                 gpointer user_data = NULL;
921                 gdk_window_get_user_data (priv->socket_window, &user_data);
922
923                 if (user_data)
924                   {
925                     g_warning (G_STRLOC "Plug reparented unexpectedly into window in the same process");
926                     priv->socket_window = NULL;
927                     break; /* FIXME: shouldn't this unref the plug? i.e. "goto done;" instead */
928                   }
929
930                 g_object_ref (priv->socket_window);
931               }
932             else
933               {
934                 priv->socket_window = gdk_x11_window_foreign_new_for_display (display, xre->parent);
935                 if (!priv->socket_window) /* Already gone */
936                   break; /* FIXME: shouldn't this unref the plug? i.e. "goto done;" instead */
937               }
938
939             if (priv->grabbed_keys)
940               {
941                 g_hash_table_iter_init (&iter, priv->grabbed_keys);
942                 while (g_hash_table_iter_next (&iter, &key, NULL))
943                   {
944                     GrabbedKey *grabbed_key = key;
945
946                     _gtk_xembed_send_message (priv->socket_window, XEMBED_GTK_GRAB_KEY, 0,
947                                               grabbed_key->accelerator_key,
948                                               grabbed_key->accelerator_mods);
949                   }
950               }
951
952             if (!was_embedded)
953               g_signal_emit_by_name (plug, "embedded");
954
955             g_object_notify (G_OBJECT (plug), "embedded");
956           }
957
958       done:
959         g_object_unref (plug);
960         
961         break;
962       }
963     case KeyPress:
964     case KeyRelease:
965       {
966         GdkModifierType state, consumed;
967         GdkDeviceManager *device_manager;
968         GdkDevice *pointer, *keyboard;
969         GdkKeymap *keymap;
970
971         if (xevent->type == KeyPress)
972           event->key.type = GDK_KEY_PRESS;
973         else
974           event->key.type = GDK_KEY_RELEASE;
975
976         event->key.window = gdk_x11_window_lookup_for_display (display, xevent->xany.window);
977         event->key.send_event = TRUE;
978         event->key.time = xevent->xkey.time;
979         event->key.state = (GdkModifierType) xevent->xkey.state;
980         event->key.hardware_keycode = xevent->xkey.keycode;
981         event->key.keyval = GDK_KEY_VoidSymbol;
982
983         device_manager = gdk_display_get_device_manager (display);
984         pointer = gdk_device_manager_get_client_pointer (device_manager);
985         keyboard = gdk_device_get_associated_device (pointer);
986         gdk_event_set_device (event, keyboard);
987
988         keymap = gdk_keymap_get_for_display (display);
989         gdk_keymap_translate_keyboard_state (keymap,
990                                              event->key.hardware_keycode,
991                                              event->key.state,
992                                              event->key.group,
993                                              &event->key.keyval,
994                                              NULL, NULL, &consumed);
995
996         state = event->key.state & ~consumed;
997         gdk_keymap_add_virtual_modifiers (keymap, &state);
998         event->key.state |= state;
999
1000         event->key.length = 0;
1001         event->key.string = g_strdup ("");
1002
1003         /* FIXME: These should be filled in properly */
1004         event->key.group = 0;
1005         event->key.is_modifier = FALSE;
1006
1007         return_val = GDK_FILTER_TRANSLATE;
1008       }
1009     }
1010
1011   return return_val;
1012 }
1013 static void
1014 gtk_plug_realize (GtkWidget *widget)
1015 {
1016   GtkAllocation allocation;
1017   GtkPlug *plug = GTK_PLUG (widget);
1018   GtkPlugPrivate *priv = plug->priv;
1019   GtkWindow *window = GTK_WINDOW (widget);
1020   GdkWindow *gdk_window;
1021   GdkWindowAttr attributes;
1022   const gchar *title;
1023   gchar *wmclass_name, *wmclass_class;
1024   gint attributes_mask;
1025
1026   gtk_widget_set_realized (widget, TRUE);
1027
1028   title = gtk_window_get_title (window);
1029   _gtk_window_get_wmclass (window, &wmclass_name, &wmclass_class);
1030   gtk_widget_get_allocation (widget, &allocation);
1031
1032   attributes.window_type = GDK_WINDOW_CHILD;    /* XXX GDK_WINDOW_PLUG ? */
1033   attributes.title = (gchar *) title;
1034   attributes.wmclass_name = wmclass_name;
1035   attributes.wmclass_class = wmclass_class;
1036   attributes.width = allocation.width;
1037   attributes.height = allocation.height;
1038   attributes.wclass = GDK_INPUT_OUTPUT;
1039
1040   /* this isn't right - we should match our parent's visual/colormap.
1041    * though that will require handling "foreign" colormaps */
1042   attributes.visual = gtk_widget_get_visual (widget);
1043   attributes.event_mask = gtk_widget_get_events (widget);
1044   attributes.event_mask |= (GDK_EXPOSURE_MASK |
1045                             GDK_KEY_PRESS_MASK |
1046                             GDK_KEY_RELEASE_MASK |
1047                             GDK_ENTER_NOTIFY_MASK |
1048                             GDK_LEAVE_NOTIFY_MASK |
1049                             GDK_STRUCTURE_MASK);
1050
1051   attributes_mask = GDK_WA_VISUAL;
1052   attributes_mask |= (title ? GDK_WA_TITLE : 0);
1053   attributes_mask |= (wmclass_name ? GDK_WA_WMCLASS : 0);
1054
1055   if (gtk_widget_is_toplevel (widget))
1056     {
1057       attributes.window_type = GDK_WINDOW_TOPLEVEL;
1058
1059       gdk_error_trap_push ();
1060       if (priv->socket_window)
1061         gdk_window = gdk_window_new (priv->socket_window,
1062                                      &attributes, attributes_mask);
1063       else /* If it's a passive plug, we use the root window */
1064         gdk_window = gdk_window_new (gtk_widget_get_root_window (widget),
1065                                      &attributes, attributes_mask);
1066       gtk_widget_set_window (widget, gdk_window);
1067
1068       gdk_display_sync (gtk_widget_get_display (widget));
1069       if (gdk_error_trap_pop ()) /* Uh-oh */
1070         {
1071           gdk_error_trap_push ();
1072           gdk_window_destroy (gdk_window);
1073           gdk_error_trap_pop_ignored ();
1074           gdk_window = gdk_window_new (gtk_widget_get_root_window (widget),
1075                                    &attributes, attributes_mask);
1076           gtk_widget_set_window (widget, gdk_window);
1077         }
1078
1079       gdk_window_add_filter (gdk_window,
1080                              gtk_plug_filter_func,
1081                              widget);
1082
1083       priv->modality_group = gtk_window_group_new ();
1084       gtk_window_group_add_window (priv->modality_group, window);
1085
1086       xembed_set_info (gtk_widget_get_window (GTK_WIDGET (plug)), 0);
1087     }
1088   else
1089     {
1090       gdk_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1091                                    &attributes, attributes_mask);
1092       gtk_widget_set_window (widget, gdk_window);
1093     }
1094
1095   gdk_window_set_user_data (gdk_window, window);
1096
1097   gtk_style_context_set_background (gtk_widget_get_style_context (widget),
1098                                     gdk_window);
1099
1100   gdk_window_enable_synchronized_configure (gdk_window);
1101 }
1102
1103 static void
1104 gtk_plug_show (GtkWidget *widget)
1105 {
1106   if (gtk_widget_is_toplevel (widget))
1107     GTK_WIDGET_CLASS (gtk_plug_parent_class)->show (widget);
1108   else
1109     GTK_WIDGET_CLASS (bin_class)->show (widget);
1110 }
1111
1112 static void
1113 gtk_plug_hide (GtkWidget *widget)
1114 {
1115   if (gtk_widget_is_toplevel (widget))
1116     GTK_WIDGET_CLASS (gtk_plug_parent_class)->hide (widget);
1117   else
1118     GTK_WIDGET_CLASS (bin_class)->hide (widget);
1119 }
1120
1121 /* From gdkinternals.h */
1122 void gdk_synthesize_window_state (GdkWindow     *window,
1123                                   GdkWindowState unset_flags,
1124                                   GdkWindowState set_flags);
1125
1126 static void
1127 gtk_plug_map (GtkWidget *widget)
1128 {
1129   if (gtk_widget_is_toplevel (widget))
1130     {
1131       GtkBin *bin = GTK_BIN (widget);
1132       GtkPlug *plug = GTK_PLUG (widget);
1133       GtkWidget *child;
1134
1135       gtk_widget_set_mapped (widget, TRUE);
1136
1137       child = gtk_bin_get_child (bin);
1138       if (child != NULL &&
1139           gtk_widget_get_visible (child) &&
1140           !gtk_widget_get_mapped (child))
1141         gtk_widget_map (child);
1142
1143       xembed_set_info (gtk_widget_get_window (GTK_WIDGET (plug)), XEMBED_MAPPED);
1144
1145       gdk_synthesize_window_state (gtk_widget_get_window (widget),
1146                                    GDK_WINDOW_STATE_WITHDRAWN,
1147                                    0);
1148     }
1149   else
1150     GTK_WIDGET_CLASS (bin_class)->map (widget);
1151 }
1152
1153 static void
1154 gtk_plug_unmap (GtkWidget *widget)
1155 {
1156   if (gtk_widget_is_toplevel (widget))
1157     {
1158       GtkPlug *plug = GTK_PLUG (widget);
1159       GdkWindow *window;
1160       GtkWidget *child;
1161
1162       window = gtk_widget_get_window (widget);
1163
1164       gtk_widget_set_mapped (widget, FALSE);
1165
1166       gdk_window_hide (window);
1167
1168       child = gtk_bin_get_child (GTK_BIN (widget));
1169       if (child != NULL)
1170         gtk_widget_unmap (child);
1171
1172       xembed_set_info (gtk_widget_get_window (GTK_WIDGET (plug)), 0);
1173
1174       gdk_synthesize_window_state (window,
1175                                    0,
1176                                    GDK_WINDOW_STATE_WITHDRAWN);
1177     }
1178   else
1179     GTK_WIDGET_CLASS (bin_class)->unmap (widget);
1180 }
1181
1182 static void
1183 gtk_plug_size_allocate (GtkWidget     *widget,
1184                         GtkAllocation *allocation)
1185 {
1186   GtkWidget *child;
1187
1188   if (gtk_widget_is_toplevel (widget))
1189     GTK_WIDGET_CLASS (gtk_plug_parent_class)->size_allocate (widget, allocation);
1190   else
1191     {
1192       GtkBin *bin = GTK_BIN (widget);
1193
1194       gtk_widget_set_allocation (widget, allocation);
1195
1196       if (gtk_widget_get_realized (widget))
1197         gdk_window_move_resize (gtk_widget_get_window (widget),
1198                                 allocation->x, allocation->y,
1199                                 allocation->width, allocation->height);
1200
1201       child = gtk_bin_get_child (bin);
1202
1203       if (child != NULL && gtk_widget_get_visible (child))
1204         {
1205           GtkAllocation child_allocation;
1206           
1207           child_allocation.x = child_allocation.y = gtk_container_get_border_width (GTK_CONTAINER (widget));
1208           child_allocation.width =
1209             MAX (1, (gint)allocation->width - child_allocation.x * 2);
1210           child_allocation.height =
1211             MAX (1, (gint)allocation->height - child_allocation.y * 2);
1212           
1213           gtk_widget_size_allocate (child, &child_allocation);
1214         }
1215       
1216     }
1217 }
1218
1219 static gboolean
1220 gtk_plug_key_press_event (GtkWidget   *widget,
1221                           GdkEventKey *event)
1222 {
1223   if (gtk_widget_is_toplevel (widget))
1224     return GTK_WIDGET_CLASS (gtk_plug_parent_class)->key_press_event (widget, event);
1225   else
1226     return FALSE;
1227 }
1228
1229 static gboolean
1230 gtk_plug_focus_event (GtkWidget      *widget,
1231                       GdkEventFocus  *event)
1232 {
1233   /* We eat focus-in events and focus-out events, since they
1234    * can be generated by something like a keyboard grab on
1235    * a child of the plug.
1236    */
1237   return FALSE;
1238 }
1239
1240 static void
1241 gtk_plug_set_focus (GtkWindow *window,
1242                     GtkWidget *focus)
1243 {
1244   GtkPlug *plug = GTK_PLUG (window);
1245   GtkPlugPrivate *priv = plug->priv;
1246
1247   GTK_WINDOW_CLASS (gtk_plug_parent_class)->set_focus (window, focus);
1248   
1249   /* Ask for focus from embedder
1250    */
1251
1252   if (focus && !gtk_window_has_toplevel_focus (window))
1253     _gtk_xembed_send_message (priv->socket_window,
1254                               XEMBED_REQUEST_FOCUS, 0, 0, 0);
1255 }
1256
1257 static guint
1258 grabbed_key_hash (gconstpointer a)
1259 {
1260   const GrabbedKey *key = a;
1261   guint h;
1262   
1263   h = key->accelerator_key << 16;
1264   h ^= key->accelerator_key >> 16;
1265   h ^= key->accelerator_mods;
1266
1267   return h;
1268 }
1269
1270 static gboolean
1271 grabbed_key_equal (gconstpointer a, gconstpointer b)
1272 {
1273   const GrabbedKey *keya = a;
1274   const GrabbedKey *keyb = b;
1275
1276   return (keya->accelerator_key == keyb->accelerator_key &&
1277           keya->accelerator_mods == keyb->accelerator_mods);
1278 }
1279
1280 static void
1281 add_grabbed_key (gpointer key, gpointer val, gpointer data)
1282 {
1283   GrabbedKey *grabbed_key = key;
1284   GtkPlug *plug = data;
1285   GtkPlugPrivate *priv = plug->priv;
1286
1287   if (!priv->grabbed_keys ||
1288       !g_hash_table_lookup (priv->grabbed_keys, grabbed_key))
1289     {
1290       _gtk_xembed_send_message (priv->socket_window, XEMBED_GTK_GRAB_KEY, 0,
1291                                 grabbed_key->accelerator_key,
1292                                 grabbed_key->accelerator_mods);
1293     }
1294 }
1295
1296 static void
1297 remove_grabbed_key (gpointer key, gpointer val, gpointer data)
1298 {
1299   GrabbedKey *grabbed_key = key;
1300   GtkPlug *plug = data;
1301   GtkPlugPrivate *priv = plug->priv;
1302
1303   if (!priv->grabbed_keys ||
1304       !g_hash_table_lookup (priv->grabbed_keys, grabbed_key))
1305     {
1306       _gtk_xembed_send_message (priv->socket_window, XEMBED_GTK_UNGRAB_KEY, 0,
1307                                 grabbed_key->accelerator_key,
1308                                 grabbed_key->accelerator_mods);
1309     }
1310 }
1311
1312 static void
1313 keys_foreach (GtkWindow      *window,
1314               guint           keyval,
1315               GdkModifierType modifiers,
1316               gboolean        is_mnemonic,
1317               gpointer        data)
1318 {
1319   GHashTable *new_grabbed_keys = data;
1320   GrabbedKey *key = g_slice_new (GrabbedKey);
1321
1322   key->accelerator_key = keyval;
1323   key->accelerator_mods = modifiers;
1324   
1325   g_hash_table_replace (new_grabbed_keys, key, key);
1326 }
1327
1328 static void
1329 grabbed_key_free (gpointer data)
1330 {
1331   g_slice_free (GrabbedKey, data);
1332 }
1333
1334 static void
1335 gtk_plug_keys_changed (GtkWindow *window)
1336 {
1337   GHashTable *new_grabbed_keys, *old_grabbed_keys;
1338   GtkPlug *plug = GTK_PLUG (window);
1339   GtkPlugPrivate *priv = plug->priv;
1340
1341   new_grabbed_keys = g_hash_table_new_full (grabbed_key_hash, grabbed_key_equal, (GDestroyNotify)grabbed_key_free, NULL);
1342   _gtk_window_keys_foreach (window, keys_foreach, new_grabbed_keys);
1343
1344   if (priv->socket_window)
1345     g_hash_table_foreach (new_grabbed_keys, add_grabbed_key, plug);
1346
1347   old_grabbed_keys = priv->grabbed_keys;
1348   priv->grabbed_keys = new_grabbed_keys;
1349
1350   if (old_grabbed_keys)
1351     {
1352       if (priv->socket_window)
1353         g_hash_table_foreach (old_grabbed_keys, remove_grabbed_key, plug);
1354       g_hash_table_destroy (old_grabbed_keys);
1355     }
1356 }
1357
1358 static void
1359 gtk_plug_focus_to_parent (GtkPlug         *plug,
1360                           GtkDirectionType direction)
1361 {
1362   GtkPlugPrivate *priv = plug->priv;
1363   XEmbedMessageType message;
1364   
1365   switch (direction)
1366     {
1367     case GTK_DIR_UP:
1368     case GTK_DIR_LEFT:
1369     case GTK_DIR_TAB_BACKWARD:
1370       message = XEMBED_FOCUS_PREV;
1371       break;
1372     case GTK_DIR_DOWN:
1373     case GTK_DIR_RIGHT:
1374     case GTK_DIR_TAB_FORWARD:
1375       message = XEMBED_FOCUS_NEXT;
1376       break;
1377     default:
1378       g_assert_not_reached ();
1379       message = XEMBED_FOCUS_PREV;
1380       break;
1381     }
1382
1383   _gtk_xembed_send_focus_message (priv->socket_window, message, 0);
1384 }
1385
1386 static gboolean
1387 gtk_plug_focus (GtkWidget        *widget,
1388                 GtkDirectionType  direction)
1389 {
1390   GtkBin *bin = GTK_BIN (widget);
1391   GtkPlug *plug = GTK_PLUG (widget);
1392   GtkWindow *window = GTK_WINDOW (widget);
1393   GtkContainer *container = GTK_CONTAINER (widget);
1394   GtkWidget *child;
1395   GtkWidget *old_focus_child;
1396   GtkWidget *parent;
1397
1398   old_focus_child = gtk_container_get_focus_child (container);
1399   /* We override GtkWindow's behavior, since we don't want wrapping here.
1400    */
1401   if (old_focus_child)
1402     {
1403       GtkWidget *focus_widget;
1404
1405       if (gtk_widget_child_focus (old_focus_child, direction))
1406         return TRUE;
1407
1408       focus_widget = gtk_window_get_focus (window);
1409       if (focus_widget)
1410         {
1411           /* Wrapped off the end, clear the focus setting for the toplevel */
1412           parent = gtk_widget_get_parent (focus_widget);
1413           while (parent)
1414             {
1415               gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
1416               parent = gtk_widget_get_parent (parent);
1417             }
1418           
1419           gtk_window_set_focus (GTK_WINDOW (container), NULL);
1420         }
1421     }
1422   else
1423     {
1424       /* Try to focus the first widget in the window */
1425       child = gtk_bin_get_child (bin);
1426       if (child && gtk_widget_child_focus (child, direction))
1427         return TRUE;
1428     }
1429
1430   if (!gtk_container_get_focus_child (GTK_CONTAINER (window)))
1431     gtk_plug_focus_to_parent (plug, direction);
1432
1433   return FALSE;
1434 }
1435
1436 static void
1437 gtk_plug_check_resize (GtkContainer *container)
1438 {
1439   if (gtk_widget_is_toplevel (GTK_WIDGET (container)))
1440     GTK_CONTAINER_CLASS (gtk_plug_parent_class)->check_resize (container);
1441   else
1442     GTK_CONTAINER_CLASS (bin_class)->check_resize (container);
1443 }
1444