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