]> Pileus Git - ~andy/gtk/blob - gtk/gtkplug.c
plug: Use Window instead of GdkNativeWindow
[~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  * @See_also: #GtkSocket
48  *
49  * Together with #GtkSocket, #GtkPlug provides the ability
50  * to embed widgets from one process into another process
51  * in a fashion that is transparent to the user. One
52  * process creates a #GtkSocket widget and passes the
53  * ID of that widget's window to the other process,
54  * which then creates a #GtkPlug with that window ID.
55  * Any widgets contained in the #GtkPlug then will appear
56  * inside the first 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, e.g.
61  * <application>Qt</application>, allowing the same level of integration
62  * when embedding a <application>Qt</application> widget in GTK or vice versa.
63  *
64  * <note>
65  * The #GtkPlug and #GtkSocket widgets are only available when GTK is
66  * compiled for the X11 platform and %GDK_WINDOWING_X11 is defined.
67  * They can only be used on a #GdkX11Display.
68  * </note>
69  */
70
71 struct _GtkPlugPrivate
72 {
73   GtkWidget      *modality_window;
74   GtkWindowGroup *modality_group;
75
76   GdkWindow      *socket_window;
77
78   GHashTable     *grabbed_keys;
79
80   guint  same_app : 1;
81 };
82
83 static void            gtk_plug_get_property          (GObject     *object,
84                                                        guint        prop_id,
85                                                        GValue      *value,
86                                                        GParamSpec  *pspec);
87 static void            gtk_plug_finalize              (GObject          *object);
88 static void            gtk_plug_realize               (GtkWidget        *widget);
89 static void            gtk_plug_unrealize             (GtkWidget        *widget);
90 static void            gtk_plug_show                  (GtkWidget        *widget);
91 static void            gtk_plug_hide                  (GtkWidget        *widget);
92 static void            gtk_plug_map                   (GtkWidget        *widget);
93 static void            gtk_plug_unmap                 (GtkWidget        *widget);
94 static void            gtk_plug_size_allocate         (GtkWidget        *widget,
95                                                        GtkAllocation    *allocation);
96 static gboolean        gtk_plug_key_press_event       (GtkWidget        *widget,
97                                                        GdkEventKey      *event);
98 static gboolean        gtk_plug_focus_event           (GtkWidget        *widget,
99                                                        GdkEventFocus    *event);
100 static void            gtk_plug_set_focus             (GtkWindow        *window,
101                                                        GtkWidget        *focus);
102 static gboolean        gtk_plug_focus                 (GtkWidget        *widget,
103                                                        GtkDirectionType  direction);
104 static void            gtk_plug_check_resize          (GtkContainer     *container);
105 static void            gtk_plug_keys_changed          (GtkWindow        *window);
106
107 static void            xembed_set_info                (GdkWindow        *window,
108                                                        unsigned long     flags);
109
110 static GtkBinClass *bin_class = NULL;
111
112 typedef struct
113 {
114   guint                  accelerator_key;
115   GdkModifierType        accelerator_mods;
116 } GrabbedKey;
117
118 enum {
119   PROP_0,
120   PROP_EMBEDDED,
121   PROP_SOCKET_WINDOW
122 };
123
124 enum {
125   EMBEDDED,
126   LAST_SIGNAL
127 }; 
128
129 static guint plug_signals[LAST_SIGNAL] = { 0 };
130
131 G_DEFINE_TYPE (GtkPlug, gtk_plug, GTK_TYPE_WINDOW)
132
133 static void
134 gtk_plug_get_property (GObject    *object,
135                        guint       prop_id,
136                        GValue     *value,
137                        GParamSpec *pspec)
138 {
139   GtkPlug *plug = GTK_PLUG (object);
140   GtkPlugPrivate *priv = plug->priv;
141
142   switch (prop_id)
143     {
144     case PROP_EMBEDDED:
145       g_value_set_boolean (value, priv->socket_window != NULL);
146       break;
147     case PROP_SOCKET_WINDOW:
148       g_value_set_object (value, priv->socket_window);
149       break;
150     default:
151       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
152       break;
153     }
154 }
155
156 static void
157 gtk_plug_class_init (GtkPlugClass *class)
158 {
159   GObjectClass *gobject_class = (GObjectClass *)class;
160   GtkWidgetClass *widget_class = (GtkWidgetClass *)class;
161   GtkWindowClass *window_class = (GtkWindowClass *)class;
162   GtkContainerClass *container_class = (GtkContainerClass *)class;
163
164   bin_class = g_type_class_peek (GTK_TYPE_BIN);
165
166   gobject_class->get_property = gtk_plug_get_property;
167   gobject_class->finalize = gtk_plug_finalize;
168   
169   widget_class->realize = gtk_plug_realize;
170   widget_class->unrealize = gtk_plug_unrealize;
171   widget_class->key_press_event = gtk_plug_key_press_event;
172   widget_class->focus_in_event = gtk_plug_focus_event;
173   widget_class->focus_out_event = gtk_plug_focus_event;
174
175   widget_class->show = gtk_plug_show;
176   widget_class->hide = gtk_plug_hide;
177   widget_class->map = gtk_plug_map;
178   widget_class->unmap = gtk_plug_unmap;
179   widget_class->size_allocate = gtk_plug_size_allocate;
180
181   widget_class->focus = gtk_plug_focus;
182
183   container_class->check_resize = gtk_plug_check_resize;
184
185   window_class->set_focus = gtk_plug_set_focus;
186   window_class->keys_changed = gtk_plug_keys_changed;
187
188   /**
189    * GtkPlug:embedded:
190    *
191    * %TRUE if the plug is embedded in a socket.
192    *
193    * Since: 2.12
194    */
195   g_object_class_install_property (gobject_class,
196                                    PROP_EMBEDDED,
197                                    g_param_spec_boolean ("embedded",
198                                                          P_("Embedded"),
199                                                          P_("Whether the plug is embedded"),
200                                                          FALSE,
201                                                          GTK_PARAM_READABLE));
202
203   /**
204    * GtkPlug:socket-window:
205    *
206    * The window of the socket the plug is embedded in.
207    *
208    * Since: 2.14
209    */
210   g_object_class_install_property (gobject_class,
211                                    PROP_SOCKET_WINDOW,
212                                    g_param_spec_object ("socket-window",
213                                                         P_("Socket Window"),
214                                                         P_("The window of the socket the plug is embedded in"),
215                                                         GDK_TYPE_WINDOW,
216                                                         GTK_PARAM_READABLE));
217
218   /**
219    * GtkPlug::embedded:
220    * @plug: the object on which the signal was emitted
221    *
222    * Gets emitted when the plug becomes embedded in a socket.
223    */ 
224   plug_signals[EMBEDDED] =
225     g_signal_new (I_("embedded"),
226                   G_OBJECT_CLASS_TYPE (class),
227                   G_SIGNAL_RUN_LAST,
228                   G_STRUCT_OFFSET (GtkPlugClass, embedded),
229                   NULL, NULL,
230                   _gtk_marshal_VOID__VOID,
231                   G_TYPE_NONE, 0);
232
233   g_type_class_add_private (class, sizeof (GtkPlugPrivate));
234 }
235
236 static void
237 gtk_plug_init (GtkPlug *plug)
238 {
239   plug->priv = G_TYPE_INSTANCE_GET_PRIVATE (plug,
240                                             GTK_TYPE_PLUG,
241                                             GtkPlugPrivate);
242 }
243
244 /**
245  * gtk_plug_handle_modality_on:
246  *
247  * @plug: a #GtkPlug
248  *
249  * Called from the GtkPlug backend when the corresponding socket has
250  * told the plug that it modality has toggled on.
251  */
252 static void
253 gtk_plug_handle_modality_on (GtkPlug *plug)
254 {
255   GtkPlugPrivate *priv = plug->priv;
256
257   if (!priv->modality_window)
258     {
259       priv->modality_window = gtk_window_new (GTK_WINDOW_POPUP);
260       gtk_window_set_screen (GTK_WINDOW (priv->modality_window),
261                              gtk_widget_get_screen (GTK_WIDGET (plug)));
262       gtk_widget_realize (priv->modality_window);
263       gtk_window_group_add_window (priv->modality_group, GTK_WINDOW (priv->modality_window));
264       gtk_grab_add (priv->modality_window);
265     }
266 }
267
268 /**
269  * gtk_plug_handle_modality_off:
270  *
271  * @plug: a #GtkPlug
272  *
273  * Called from the GtkPlug backend when the corresponding socket has
274  * told the plug that it modality has toggled off.
275  */
276 static void
277 gtk_plug_handle_modality_off (GtkPlug *plug)
278 {
279   GtkPlugPrivate *priv = plug->priv;
280
281   if (priv->modality_window)
282     {
283       gtk_widget_destroy (priv->modality_window);
284       priv->modality_window = NULL;
285     }
286 }
287
288 static void
289 gtk_plug_set_is_child (GtkPlug  *plug,
290                        gboolean  is_child)
291 {
292   GtkPlugPrivate *priv = plug->priv;
293   GtkWidget *widget = GTK_WIDGET (plug);
294
295   g_assert (!gtk_widget_get_parent (widget));
296
297   if (is_child)
298     {
299       if (priv->modality_window)
300         gtk_plug_handle_modality_off (plug);
301
302       if (priv->modality_group)
303         {
304           gtk_window_group_remove_window (priv->modality_group, GTK_WINDOW (plug));
305           g_object_unref (priv->modality_group);
306           priv->modality_group = NULL;
307         }
308       
309       /* As a toplevel, the MAPPED flag doesn't correspond
310        * to whether the widget->window is mapped; we unmap
311        * here, but don't bother remapping -- we will get mapped
312        * by gtk_widget_set_parent ().
313        */
314       if (gtk_widget_get_mapped (widget))
315         gtk_widget_unmap (widget);
316
317       _gtk_window_set_is_toplevel (GTK_WINDOW (plug), FALSE);
318       gtk_container_set_resize_mode (GTK_CONTAINER (plug), GTK_RESIZE_PARENT);
319
320       _gtk_widget_propagate_hierarchy_changed (widget, widget);
321     }
322   else
323     {
324       if (gtk_window_get_focus (GTK_WINDOW (plug)))
325         gtk_window_set_focus (GTK_WINDOW (plug), NULL);
326       if (gtk_window_get_default_widget (GTK_WINDOW (plug)))
327         gtk_window_set_default (GTK_WINDOW (plug), NULL);
328
329       priv->modality_group = gtk_window_group_new ();
330       gtk_window_group_add_window (priv->modality_group, GTK_WINDOW (plug));
331
332       _gtk_window_set_is_toplevel (GTK_WINDOW (plug), TRUE);
333       gtk_container_set_resize_mode (GTK_CONTAINER (plug), GTK_RESIZE_QUEUE);
334
335       _gtk_widget_propagate_hierarchy_changed (GTK_WIDGET (plug), NULL);
336     }
337 }
338
339 /**
340  * gtk_plug_get_id:
341  * @plug: a #GtkPlug.
342  * 
343  * Gets the window ID of a #GtkPlug widget, which can then
344  * be used to embed this window inside another window, for
345  * instance with gtk_socket_add_id().
346  * 
347  * Return value: the window ID for the plug
348  **/
349 Window
350 gtk_plug_get_id (GtkPlug *plug)
351 {
352   g_return_val_if_fail (GTK_IS_PLUG (plug), 0);
353
354   if (!gtk_widget_get_realized (GTK_WIDGET (plug)))
355     gtk_widget_realize (GTK_WIDGET (plug));
356
357   return GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (plug)));
358 }
359
360 /**
361  * gtk_plug_get_embedded:
362  * @plug: a #GtkPlug
363  *
364  * Determines whether the plug is embedded in a socket.
365  *
366  * Return value: %TRUE if the plug is embedded in a socket
367  *
368  * Since: 2.14
369  **/
370 gboolean
371 gtk_plug_get_embedded (GtkPlug *plug)
372 {
373   g_return_val_if_fail (GTK_IS_PLUG (plug), FALSE);
374
375   return plug->priv->socket_window != NULL;
376 }
377
378 /**
379  * gtk_plug_get_socket_window:
380  * @plug: a #GtkPlug
381  *
382  * Retrieves the socket the plug is embedded in.
383  *
384  * Return value: (transfer none): the window of the socket, or %NULL
385  *
386  * Since: 2.14
387  **/
388 GdkWindow *
389 gtk_plug_get_socket_window (GtkPlug *plug)
390 {
391   g_return_val_if_fail (GTK_IS_PLUG (plug), NULL);
392
393   return plug->priv->socket_window;
394 }
395
396 /**
397  * _gtk_plug_add_to_socket:
398  * @plug: a #GtkPlug
399  * @socket_: a #GtkSocket
400  * 
401  * Adds a plug to a socket within the same application.
402  **/
403 void
404 _gtk_plug_add_to_socket (GtkPlug   *plug,
405                          GtkSocket *socket_)
406 {
407   GtkPlugPrivate *priv;
408   GtkWidget *widget;
409   
410   g_return_if_fail (GTK_IS_PLUG (plug));
411   g_return_if_fail (GTK_IS_SOCKET (socket_));
412   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (socket_)));
413
414   priv = plug->priv;
415   widget = GTK_WIDGET (plug);
416
417   gtk_plug_set_is_child (plug, TRUE);
418   priv->same_app = TRUE;
419   socket_->priv->same_app = TRUE;
420   socket_->priv->plug_widget = widget;
421
422   priv->socket_window = gtk_widget_get_window (GTK_WIDGET (socket_));
423   g_object_ref (priv->socket_window);
424   g_signal_emit (plug, plug_signals[EMBEDDED], 0);
425   g_object_notify (G_OBJECT (plug), "embedded");
426
427   if (gtk_widget_get_realized (widget))
428     {
429       GdkWindow *window;
430
431       window = gtk_widget_get_window (widget);
432       gdk_window_reparent (window, priv->socket_window,
433                            -gdk_window_get_width (window),
434                            -gdk_window_get_height (window));
435     }
436
437   gtk_widget_set_parent (widget, GTK_WIDGET (socket_));
438
439   g_signal_emit_by_name (socket_, "plug-added");
440 }
441
442 /**
443  * _gtk_plug_send_delete_event:
444  * @widget: a #GtkWidget
445  *
446  * Send a GDK_DELETE event to the @widget and destroy it if
447  * necessary. Internal GTK function, called from this file or the
448  * backend-specific GtkPlug implementation.
449  */
450 void
451 _gtk_plug_send_delete_event (GtkWidget *widget)
452 {
453   GdkEvent *event = gdk_event_new (GDK_DELETE);
454
455   event->any.window = g_object_ref (gtk_widget_get_window (widget));
456   event->any.send_event = FALSE;
457
458   g_object_ref (widget);
459
460   if (!gtk_widget_event (widget, event))
461     gtk_widget_destroy (widget);
462
463   g_object_unref (widget);
464
465   gdk_event_free (event);
466 }
467
468 /**
469  * _gtk_plug_remove_from_socket:
470  * @plug: a #GtkPlug
471  * @socket_: a #GtkSocket
472  * 
473  * Removes a plug from a socket within the same application.
474  **/
475 void
476 _gtk_plug_remove_from_socket (GtkPlug   *plug,
477                               GtkSocket *socket_)
478 {
479   GtkPlugPrivate *priv;
480   GtkWidget *widget;
481   GdkWindow *window;
482   gboolean result;
483   gboolean widget_was_visible;
484
485   g_return_if_fail (GTK_IS_PLUG (plug));
486   g_return_if_fail (GTK_IS_SOCKET (socket_));
487   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (plug)));
488
489   priv = plug->priv;
490   widget = GTK_WIDGET (plug);
491
492   if (_gtk_widget_get_in_reparent (widget))
493     return;
494
495   g_object_ref (plug);
496   g_object_ref (socket_);
497
498   widget_was_visible = gtk_widget_get_visible (widget);
499   window = gtk_widget_get_window (widget);
500
501   gdk_window_hide (window);
502   _gtk_widget_set_in_reparent (widget, TRUE);
503   gdk_window_reparent (window,
504                        gtk_widget_get_root_window (widget),
505                        0, 0);
506   gtk_widget_unparent (GTK_WIDGET (plug));
507   _gtk_widget_set_in_reparent (widget, FALSE);
508   
509   socket_->priv->plug_widget = NULL;
510   if (socket_->priv->plug_window != NULL)
511     {
512       g_object_unref (socket_->priv->plug_window);
513       socket_->priv->plug_window = NULL;
514     }
515   
516   socket_->priv->same_app = FALSE;
517
518   priv->same_app = FALSE;
519   if (priv->socket_window != NULL)
520     {
521       g_object_unref (priv->socket_window);
522       priv->socket_window = NULL;
523     }
524   gtk_plug_set_is_child (plug, FALSE);
525
526   g_signal_emit_by_name (socket_, "plug-removed", &result);
527   if (!result)
528     gtk_widget_destroy (GTK_WIDGET (socket_));
529
530   if (window)
531     _gtk_plug_send_delete_event (widget);
532
533   g_object_unref (plug);
534
535   if (widget_was_visible && gtk_widget_get_visible (GTK_WIDGET (socket_)))
536     gtk_widget_queue_resize (GTK_WIDGET (socket_));
537
538   g_object_unref (socket_);
539 }
540
541 /**
542  * gtk_plug_construct:
543  * @plug: a #GtkPlug.
544  * @socket_id: the XID of the socket's window.
545  *
546  * Finish the initialization of @plug for a given #GtkSocket identified by
547  * @socket_id. This function will generally only be used by classes deriving from #GtkPlug.
548  **/
549 void
550 gtk_plug_construct (GtkPlug *plug,
551                     Window   socket_id)
552 {
553   gtk_plug_construct_for_display (plug, gdk_display_get_default (), socket_id);
554 }
555
556 /**
557  * gtk_plug_construct_for_display:
558  * @plug: a #GtkPlug.
559  * @display: the #GdkDisplay associated with @socket_id's 
560  *           #GtkSocket.
561  * @socket_id: the XID of the socket's window.
562  *
563  * Finish the initialization of @plug for a given #GtkSocket identified by
564  * @socket_id which is currently displayed on @display.
565  * This function will generally only be used by classes deriving from #GtkPlug.
566  *
567  * Since: 2.2
568  **/
569 void
570 gtk_plug_construct_for_display (GtkPlug    *plug,
571                                 GdkDisplay *display,
572                                 Window      socket_id)
573 {
574   GtkPlugPrivate *priv;
575
576   g_return_if_fail (GTK_IS_PLUG (plug));
577   g_return_if_fail (GDK_IS_DISPLAY (display));
578
579   priv = plug->priv;
580
581   if (socket_id)
582     {
583       gpointer user_data = NULL;
584
585       if (GDK_IS_X11_DISPLAY (display))
586         priv->socket_window = gdk_x11_window_lookup_for_display (display, socket_id);
587       else
588         priv->socket_window = NULL;
589
590       if (priv->socket_window)
591         {
592           gdk_window_get_user_data (priv->socket_window, &user_data);
593
594           if (user_data)
595             {
596               if (GTK_IS_SOCKET (user_data))
597                 _gtk_plug_add_to_socket (plug, user_data);
598               else
599                 {
600                   g_warning (G_STRLOC "Can't create GtkPlug as child of non-GtkSocket");
601                   priv->socket_window = NULL;
602                 }
603             }
604           else
605             g_object_ref (priv->socket_window);
606         }
607       else if (GDK_IS_X11_DISPLAY (display))
608         priv->socket_window = gdk_x11_window_foreign_new_for_display (display, socket_id);
609
610       if (priv->socket_window) {
611         g_signal_emit (plug, plug_signals[EMBEDDED], 0);
612
613         g_object_notify (G_OBJECT (plug), "embedded");
614       }
615     }
616 }
617
618 /**
619  * gtk_plug_new:
620  * @socket_id:  the window ID of the socket, or 0.
621  * 
622  * Creates a new plug widget inside the #GtkSocket identified
623  * by @socket_id. If @socket_id is 0, the plug is left "unplugged" and
624  * can later be plugged into a #GtkSocket by  gtk_socket_add_id().
625  * 
626  * Return value: the new #GtkPlug widget.
627  **/
628 GtkWidget*
629 gtk_plug_new (Window socket_id)
630 {
631   return gtk_plug_new_for_display (gdk_display_get_default (), socket_id);
632 }
633
634 /**
635  * gtk_plug_new_for_display:
636  * @display: the #GdkDisplay on which @socket_id is displayed
637  * @socket_id: the XID of the socket's window.
638  * 
639  * Create a new plug widget inside the #GtkSocket identified by socket_id.
640  *
641  * Return value: the new #GtkPlug widget.
642  *
643  * Since: 2.2
644  */
645 GtkWidget*
646 gtk_plug_new_for_display (GdkDisplay *display,
647                           Window      socket_id)
648 {
649   GtkPlug *plug;
650
651   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
652
653   plug = g_object_new (GTK_TYPE_PLUG, NULL);
654   gtk_plug_construct_for_display (plug, display, socket_id);
655   return GTK_WIDGET (plug);
656 }
657
658 static void
659 gtk_plug_finalize (GObject *object)
660 {
661   GtkPlug *plug = GTK_PLUG (object);
662   GtkPlugPrivate *priv = plug->priv;
663
664   if (priv->grabbed_keys)
665     {
666       g_hash_table_destroy (priv->grabbed_keys);
667       priv->grabbed_keys = NULL;
668     }
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             g_hash_table_iter_init (&iter, priv->grabbed_keys);
938
939             while (g_hash_table_iter_next (&iter, &key, NULL))
940               {
941                 GrabbedKey *grabbed_key = key;
942
943                 _gtk_xembed_send_message (priv->socket_window, XEMBED_GTK_GRAB_KEY, 0,
944                                           grabbed_key->accelerator_key,
945                                           grabbed_key->accelerator_mods);
946               }
947
948             if (!was_embedded)
949               g_signal_emit_by_name (plug, "embedded");
950
951             g_object_notify (G_OBJECT (plug), "embedded");
952           }
953
954       done:
955         g_object_unref (plug);
956         
957         break;
958       }
959     case KeyPress:
960     case KeyRelease:
961       {
962         GdkModifierType state, consumed;
963         GdkDeviceManager *device_manager;
964         GdkDevice *pointer, *keyboard;
965         GdkKeymap *keymap;
966
967         if (xevent->type == KeyPress)
968           event->key.type = GDK_KEY_PRESS;
969         else
970           event->key.type = GDK_KEY_RELEASE;
971
972         event->key.window = gdk_x11_window_lookup_for_display (display, xevent->xany.window);
973         event->key.send_event = TRUE;
974         event->key.time = xevent->xkey.time;
975         event->key.state = (GdkModifierType) xevent->xkey.state;
976         event->key.hardware_keycode = xevent->xkey.keycode;
977         event->key.keyval = GDK_KEY_VoidSymbol;
978
979         device_manager = gdk_display_get_device_manager (display);
980         pointer = gdk_device_manager_get_client_pointer (device_manager);
981         keyboard = gdk_device_get_associated_device (pointer);
982         gdk_event_set_device (event, keyboard);
983
984         keymap = gdk_keymap_get_for_display (display);
985         gdk_keymap_translate_keyboard_state (keymap,
986                                              event->key.hardware_keycode,
987                                              event->key.state,
988                                              event->key.group,
989                                              &event->key.keyval,
990                                              NULL, NULL, &consumed);
991
992         state = event->key.state & ~consumed;
993         gdk_keymap_add_virtual_modifiers (keymap, &state);
994         event->key.state |= state;
995
996         event->key.length = 0;
997         event->key.string = g_strdup ("");
998
999         /* FIXME: These should be filled in properly */
1000         event->key.group = 0;
1001         event->key.is_modifier = FALSE;
1002
1003         return_val = GDK_FILTER_TRANSLATE;
1004       }
1005     }
1006
1007   return return_val;
1008 }
1009 static void
1010 gtk_plug_realize (GtkWidget *widget)
1011 {
1012   GtkAllocation allocation;
1013   GtkPlug *plug = GTK_PLUG (widget);
1014   GtkPlugPrivate *priv = plug->priv;
1015   GtkWindow *window = GTK_WINDOW (widget);
1016   GdkWindow *gdk_window;
1017   GdkWindowAttr attributes;
1018   const gchar *title;
1019   gchar *wmclass_name, *wmclass_class;
1020   gint attributes_mask;
1021
1022   gtk_widget_set_realized (widget, TRUE);
1023
1024   title = gtk_window_get_title (window);
1025   _gtk_window_get_wmclass (window, &wmclass_name, &wmclass_class);
1026   gtk_widget_get_allocation (widget, &allocation);
1027
1028   attributes.window_type = GDK_WINDOW_CHILD;    /* XXX GDK_WINDOW_PLUG ? */
1029   attributes.title = (gchar *) title;
1030   attributes.wmclass_name = wmclass_name;
1031   attributes.wmclass_class = wmclass_class;
1032   attributes.width = allocation.width;
1033   attributes.height = allocation.height;
1034   attributes.wclass = GDK_INPUT_OUTPUT;
1035
1036   /* this isn't right - we should match our parent's visual/colormap.
1037    * though that will require handling "foreign" colormaps */
1038   attributes.visual = gtk_widget_get_visual (widget);
1039   attributes.event_mask = gtk_widget_get_events (widget);
1040   attributes.event_mask |= (GDK_EXPOSURE_MASK |
1041                             GDK_KEY_PRESS_MASK |
1042                             GDK_KEY_RELEASE_MASK |
1043                             GDK_ENTER_NOTIFY_MASK |
1044                             GDK_LEAVE_NOTIFY_MASK |
1045                             GDK_STRUCTURE_MASK);
1046
1047   attributes_mask = GDK_WA_VISUAL;
1048   attributes_mask |= (title ? GDK_WA_TITLE : 0);
1049   attributes_mask |= (wmclass_name ? GDK_WA_WMCLASS : 0);
1050
1051   if (gtk_widget_is_toplevel (widget))
1052     {
1053       attributes.window_type = GDK_WINDOW_TOPLEVEL;
1054
1055       gdk_error_trap_push ();
1056       if (priv->socket_window)
1057         gdk_window = gdk_window_new (priv->socket_window,
1058                                      &attributes, attributes_mask);
1059       else /* If it's a passive plug, we use the root window */
1060         gdk_window = gdk_window_new (gtk_widget_get_root_window (widget),
1061                                      &attributes, attributes_mask);
1062       gtk_widget_set_window (widget, gdk_window);
1063
1064       gdk_display_sync (gtk_widget_get_display (widget));
1065       if (gdk_error_trap_pop ()) /* Uh-oh */
1066         {
1067           gdk_error_trap_push ();
1068           gdk_window_destroy (gdk_window);
1069           gdk_error_trap_pop_ignored ();
1070           gdk_window = gdk_window_new (gtk_widget_get_root_window (widget),
1071                                    &attributes, attributes_mask);
1072           gtk_widget_set_window (widget, gdk_window);
1073         }
1074
1075       gdk_window_add_filter (gdk_window,
1076                              gtk_plug_filter_func,
1077                              widget);
1078
1079       priv->modality_group = gtk_window_group_new ();
1080       gtk_window_group_add_window (priv->modality_group, window);
1081
1082       xembed_set_info (gtk_widget_get_window (GTK_WIDGET (plug)), 0);
1083     }
1084   else
1085     {
1086       gdk_window = gdk_window_new (gtk_widget_get_parent_window (widget),
1087                                    &attributes, attributes_mask);
1088       gtk_widget_set_window (widget, gdk_window);
1089     }
1090
1091   gdk_window_set_user_data (gdk_window, window);
1092
1093   gtk_style_context_set_background (gtk_widget_get_style_context (widget),
1094                                     gdk_window);
1095
1096   gdk_window_enable_synchronized_configure (gdk_window);
1097 }
1098
1099 static void
1100 gtk_plug_show (GtkWidget *widget)
1101 {
1102   if (gtk_widget_is_toplevel (widget))
1103     GTK_WIDGET_CLASS (gtk_plug_parent_class)->show (widget);
1104   else
1105     GTK_WIDGET_CLASS (bin_class)->show (widget);
1106 }
1107
1108 static void
1109 gtk_plug_hide (GtkWidget *widget)
1110 {
1111   if (gtk_widget_is_toplevel (widget))
1112     GTK_WIDGET_CLASS (gtk_plug_parent_class)->hide (widget);
1113   else
1114     GTK_WIDGET_CLASS (bin_class)->hide (widget);
1115 }
1116
1117 /* From gdkinternals.h */
1118 void gdk_synthesize_window_state (GdkWindow     *window,
1119                                   GdkWindowState unset_flags,
1120                                   GdkWindowState set_flags);
1121
1122 static void
1123 gtk_plug_map (GtkWidget *widget)
1124 {
1125   if (gtk_widget_is_toplevel (widget))
1126     {
1127       GtkBin *bin = GTK_BIN (widget);
1128       GtkPlug *plug = GTK_PLUG (widget);
1129       GtkWidget *child;
1130       
1131       gtk_widget_set_mapped (widget, TRUE);
1132
1133       child = gtk_bin_get_child (bin);
1134       if (child != NULL &&
1135           gtk_widget_get_visible (child) &&
1136           !gtk_widget_get_mapped (child))
1137         gtk_widget_map (child);
1138
1139       xembed_set_info (gtk_widget_get_window (GTK_WIDGET (plug)), XEMBED_MAPPED);
1140
1141       gdk_synthesize_window_state (gtk_widget_get_window (widget),
1142                                    GDK_WINDOW_STATE_WITHDRAWN,
1143                                    0);
1144     }
1145   else
1146     GTK_WIDGET_CLASS (bin_class)->map (widget);
1147 }
1148
1149 static void
1150 gtk_plug_unmap (GtkWidget *widget)
1151 {
1152   if (gtk_widget_is_toplevel (widget))
1153     {
1154       GtkPlug *plug = GTK_PLUG (widget);
1155       GdkWindow *window;
1156
1157       window = gtk_widget_get_window (widget);
1158
1159       gtk_widget_set_mapped (widget, FALSE);
1160
1161       gdk_window_hide (window);
1162
1163       xembed_set_info (gtk_widget_get_window (GTK_WIDGET (plug)), 0);
1164
1165       gdk_synthesize_window_state (window,
1166                                    0,
1167                                    GDK_WINDOW_STATE_WITHDRAWN);
1168     }
1169   else
1170     GTK_WIDGET_CLASS (bin_class)->unmap (widget);
1171 }
1172
1173 static void
1174 gtk_plug_size_allocate (GtkWidget     *widget,
1175                         GtkAllocation *allocation)
1176 {
1177   GtkWidget *child;
1178
1179   if (gtk_widget_is_toplevel (widget))
1180     GTK_WIDGET_CLASS (gtk_plug_parent_class)->size_allocate (widget, allocation);
1181   else
1182     {
1183       GtkBin *bin = GTK_BIN (widget);
1184
1185       gtk_widget_set_allocation (widget, allocation);
1186
1187       if (gtk_widget_get_realized (widget))
1188         gdk_window_move_resize (gtk_widget_get_window (widget),
1189                                 allocation->x, allocation->y,
1190                                 allocation->width, allocation->height);
1191
1192       child = gtk_bin_get_child (bin);
1193
1194       if (child != NULL && gtk_widget_get_visible (child))
1195         {
1196           GtkAllocation child_allocation;
1197           
1198           child_allocation.x = child_allocation.y = gtk_container_get_border_width (GTK_CONTAINER (widget));
1199           child_allocation.width =
1200             MAX (1, (gint)allocation->width - child_allocation.x * 2);
1201           child_allocation.height =
1202             MAX (1, (gint)allocation->height - child_allocation.y * 2);
1203           
1204           gtk_widget_size_allocate (child, &child_allocation);
1205         }
1206       
1207     }
1208 }
1209
1210 static gboolean
1211 gtk_plug_key_press_event (GtkWidget   *widget,
1212                           GdkEventKey *event)
1213 {
1214   if (gtk_widget_is_toplevel (widget))
1215     return GTK_WIDGET_CLASS (gtk_plug_parent_class)->key_press_event (widget, event);
1216   else
1217     return FALSE;
1218 }
1219
1220 static gboolean
1221 gtk_plug_focus_event (GtkWidget      *widget,
1222                       GdkEventFocus  *event)
1223 {
1224   /* We eat focus-in events and focus-out events, since they
1225    * can be generated by something like a keyboard grab on
1226    * a child of the plug.
1227    */
1228   return FALSE;
1229 }
1230
1231 static void
1232 gtk_plug_set_focus (GtkWindow *window,
1233                     GtkWidget *focus)
1234 {
1235   GtkPlug *plug = GTK_PLUG (window);
1236   GtkPlugPrivate *priv = plug->priv;
1237
1238   GTK_WINDOW_CLASS (gtk_plug_parent_class)->set_focus (window, focus);
1239   
1240   /* Ask for focus from embedder
1241    */
1242
1243   if (focus && !gtk_window_has_toplevel_focus (window))
1244     _gtk_xembed_send_message (priv->socket_window,
1245                               XEMBED_REQUEST_FOCUS, 0, 0, 0);
1246 }
1247
1248 static guint
1249 grabbed_key_hash (gconstpointer a)
1250 {
1251   const GrabbedKey *key = a;
1252   guint h;
1253   
1254   h = key->accelerator_key << 16;
1255   h ^= key->accelerator_key >> 16;
1256   h ^= key->accelerator_mods;
1257
1258   return h;
1259 }
1260
1261 static gboolean
1262 grabbed_key_equal (gconstpointer a, gconstpointer b)
1263 {
1264   const GrabbedKey *keya = a;
1265   const GrabbedKey *keyb = b;
1266
1267   return (keya->accelerator_key == keyb->accelerator_key &&
1268           keya->accelerator_mods == keyb->accelerator_mods);
1269 }
1270
1271 static void
1272 add_grabbed_key (gpointer key, gpointer val, gpointer data)
1273 {
1274   GrabbedKey *grabbed_key = key;
1275   GtkPlug *plug = data;
1276   GtkPlugPrivate *priv = plug->priv;
1277
1278   if (!priv->grabbed_keys ||
1279       !g_hash_table_lookup (priv->grabbed_keys, grabbed_key))
1280     {
1281       _gtk_xembed_send_message (priv->socket_window, XEMBED_GTK_GRAB_KEY, 0,
1282                                 grabbed_key->accelerator_key,
1283                                 grabbed_key->accelerator_mods);
1284     }
1285 }
1286
1287 static void
1288 remove_grabbed_key (gpointer key, gpointer val, gpointer data)
1289 {
1290   GrabbedKey *grabbed_key = key;
1291   GtkPlug *plug = data;
1292   GtkPlugPrivate *priv = plug->priv;
1293
1294   if (!priv->grabbed_keys ||
1295       !g_hash_table_lookup (priv->grabbed_keys, grabbed_key))
1296     {
1297       _gtk_xembed_send_message (priv->socket_window, XEMBED_GTK_UNGRAB_KEY, 0,
1298                                 grabbed_key->accelerator_key,
1299                                 grabbed_key->accelerator_mods);
1300     }
1301 }
1302
1303 static void
1304 keys_foreach (GtkWindow      *window,
1305               guint           keyval,
1306               GdkModifierType modifiers,
1307               gboolean        is_mnemonic,
1308               gpointer        data)
1309 {
1310   GHashTable *new_grabbed_keys = data;
1311   GrabbedKey *key = g_slice_new (GrabbedKey);
1312
1313   key->accelerator_key = keyval;
1314   key->accelerator_mods = modifiers;
1315   
1316   g_hash_table_replace (new_grabbed_keys, key, key);
1317 }
1318
1319 static void
1320 grabbed_key_free (gpointer data)
1321 {
1322   g_slice_free (GrabbedKey, data);
1323 }
1324
1325 static void
1326 gtk_plug_keys_changed (GtkWindow *window)
1327 {
1328   GHashTable *new_grabbed_keys, *old_grabbed_keys;
1329   GtkPlug *plug = GTK_PLUG (window);
1330   GtkPlugPrivate *priv = plug->priv;
1331
1332   new_grabbed_keys = g_hash_table_new_full (grabbed_key_hash, grabbed_key_equal, (GDestroyNotify)grabbed_key_free, NULL);
1333   _gtk_window_keys_foreach (window, keys_foreach, new_grabbed_keys);
1334
1335   if (priv->socket_window)
1336     g_hash_table_foreach (new_grabbed_keys, add_grabbed_key, plug);
1337
1338   old_grabbed_keys = priv->grabbed_keys;
1339   priv->grabbed_keys = new_grabbed_keys;
1340
1341   if (old_grabbed_keys)
1342     {
1343       if (priv->socket_window)
1344         g_hash_table_foreach (old_grabbed_keys, remove_grabbed_key, plug);
1345       g_hash_table_destroy (old_grabbed_keys);
1346     }
1347 }
1348
1349 static void
1350 gtk_plug_focus_to_parent (GtkPlug         *plug,
1351                           GtkDirectionType direction)
1352 {
1353   GtkPlugPrivate *priv = plug->priv;
1354   XEmbedMessageType message;
1355   
1356   switch (direction)
1357     {
1358     case GTK_DIR_UP:
1359     case GTK_DIR_LEFT:
1360     case GTK_DIR_TAB_BACKWARD:
1361       message = XEMBED_FOCUS_PREV;
1362       break;
1363     case GTK_DIR_DOWN:
1364     case GTK_DIR_RIGHT:
1365     case GTK_DIR_TAB_FORWARD:
1366       message = XEMBED_FOCUS_NEXT;
1367       break;
1368     default:
1369       g_assert_not_reached ();
1370       message = XEMBED_FOCUS_PREV;
1371       break;
1372     }
1373
1374   _gtk_xembed_send_focus_message (priv->socket_window, message, 0);
1375 }
1376
1377 static gboolean
1378 gtk_plug_focus (GtkWidget        *widget,
1379                 GtkDirectionType  direction)
1380 {
1381   GtkBin *bin = GTK_BIN (widget);
1382   GtkPlug *plug = GTK_PLUG (widget);
1383   GtkWindow *window = GTK_WINDOW (widget);
1384   GtkContainer *container = GTK_CONTAINER (widget);
1385   GtkWidget *child;
1386   GtkWidget *old_focus_child;
1387   GtkWidget *parent;
1388
1389   old_focus_child = gtk_container_get_focus_child (container);
1390   /* We override GtkWindow's behavior, since we don't want wrapping here.
1391    */
1392   if (old_focus_child)
1393     {
1394       GtkWidget *focus_widget;
1395
1396       if (gtk_widget_child_focus (old_focus_child, direction))
1397         return TRUE;
1398
1399       focus_widget = gtk_window_get_focus (window);
1400       if (focus_widget)
1401         {
1402           /* Wrapped off the end, clear the focus setting for the toplevel */
1403           parent = gtk_widget_get_parent (focus_widget);
1404           while (parent)
1405             {
1406               gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
1407               parent = gtk_widget_get_parent (parent);
1408             }
1409           
1410           gtk_window_set_focus (GTK_WINDOW (container), NULL);
1411         }
1412     }
1413   else
1414     {
1415       /* Try to focus the first widget in the window */
1416       child = gtk_bin_get_child (bin);
1417       if (child && gtk_widget_child_focus (child, direction))
1418         return TRUE;
1419     }
1420
1421   if (!gtk_container_get_focus_child (GTK_CONTAINER (window)))
1422     gtk_plug_focus_to_parent (plug, direction);
1423
1424   return FALSE;
1425 }
1426
1427 static void
1428 gtk_plug_check_resize (GtkContainer *container)
1429 {
1430   if (gtk_widget_is_toplevel (GTK_WIDGET (container)))
1431     GTK_CONTAINER_CLASS (gtk_plug_parent_class)->check_resize (container);
1432   else
1433     GTK_CONTAINER_CLASS (bin_class)->check_resize (container);
1434 }
1435