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