]> Pileus Git - ~andy/gtk/blob - gtk/gtksocket.c
Reinstate old-style deprecation guards for wholly-deprecated files
[~andy/gtk] / gtk / gtksocket.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 "gtksocketprivate.h"
30
31 #include <string.h>
32
33 #include "gtkmarshalers.h"
34 #include "gtksizerequest.h"
35 #include "gtkplug.h"
36 #include "gtkprivate.h"
37 #include "gtkdnd.h"
38 #include "gtkdebug.h"
39 #include "gtkintl.h"
40 #include "gtkmain.h"
41 #include "gtkwidgetprivate.h"
42
43 #include <gdk/gdkx.h>
44 #include <gdk/gdkprivate.h>
45
46 #ifdef HAVE_XFIXES
47 #include <X11/extensions/Xfixes.h>
48 #endif
49
50 #include "gtkxembed.h"
51
52
53 /**
54  * SECTION:gtksocket
55  * @Short_description: Container for widgets from other processes
56  * @Title: GtkSocket
57  * @include: gtk/gtkx.h
58  * @See_also: #GtkPlug, <ulink url="http://www.freedesktop.org/Standards/xembed-spec">XEmbed</ulink>
59  *
60  * Together with #GtkPlug, #GtkSocket provides the ability to embed
61  * widgets from one process into another process in a fashion that
62  * is transparent to the user. One process creates a #GtkSocket widget
63  * and passes that widget's window ID to the other process, which then
64  * creates a #GtkPlug with that window ID. Any widgets contained in the
65  * #GtkPlug then will appear inside the first application's window.
66  *
67  * The socket's window ID is obtained by using gtk_socket_get_id().
68  * Before using this function, the socket must have been realized,
69  * and for hence, have been added to its parent.
70  *
71  * <example>
72  * <title>Obtaining the window ID of a socket.</title>
73  * <programlisting>
74  * GtkWidget *socket = gtk_socket_new (<!-- -->);
75  * gtk_widget_show (socket);
76  * gtk_container_add (GTK_CONTAINER (parent), socket);
77  *
78  * /&ast; The following call is only necessary if one of
79  *  * the ancestors of the socket is not yet visible.
80  *  &ast;/
81  * gtk_widget_realize (socket);
82  * g_print ("The ID of the sockets window is %#x\n",
83  *          gtk_socket_get_id (socket));
84  * </programlisting>
85  * </example>
86  *
87  * Note that if you pass the window ID of the socket to another
88  * process that will create a plug in the socket, you must make
89  * sure that the socket widget is not destroyed until that plug
90  * is created. Violating this rule will cause unpredictable
91  * consequences, the most likely consequence being that the plug
92  * will appear as a separate toplevel window. You can check if
93  * the plug has been created by using gtk_socket_get_plug_window().
94  * If it returns a non-%NULL value, then the plug has been
95  * successfully created inside of the socket.
96  *
97  * When GTK+ is notified that the embedded window has been destroyed,
98  * then it will destroy the socket as well. You should always,
99  * therefore, be prepared for your sockets to be destroyed at any
100  * time when the main event loop is running. To prevent this from
101  * happening, you can connect to the #GtkSocket::plug-removed signal.
102  *
103  * The communication between a #GtkSocket and a #GtkPlug follows the
104  * <ulink url="http://www.freedesktop.org/Standards/xembed-spec">XEmbed</ulink>
105  * protocol. This protocol has also been implemented in other toolkits,
106  * e.g. <application>Qt</application>, allowing the same level of
107  * integration when embedding a <application>Qt</application> widget
108  * in GTK or vice versa.
109  *
110  * <note>
111  * The #GtkPlug and #GtkSocket widgets are only available when GTK+
112  * is compiled for the X11 platform and %GDK_WINDOWING_X11 is defined.
113  * They can only be used on a #GdkX11Display. To use #GtkPlug and
114  * #GtkSocket, you need to include the <filename>gtk/gtkx.h</filename>
115  * header.
116  * </note>
117  */
118
119 /* Forward declararations */
120
121 static void     gtk_socket_finalize             (GObject          *object);
122 static void     gtk_socket_notify               (GObject          *object,
123                                                  GParamSpec       *pspec);
124 static void     gtk_socket_realize              (GtkWidget        *widget);
125 static void     gtk_socket_unrealize            (GtkWidget        *widget);
126 static void     gtk_socket_get_preferred_width  (GtkWidget        *widget,
127                                                  gint             *minimum,
128                                                  gint             *natural);
129 static void     gtk_socket_get_preferred_height (GtkWidget        *widget,
130                                                  gint             *minimum,
131                                                  gint             *natural);
132 static void     gtk_socket_size_allocate        (GtkWidget        *widget,
133                                                  GtkAllocation    *allocation);
134 static void     gtk_socket_hierarchy_changed    (GtkWidget        *widget,
135                                                  GtkWidget        *old_toplevel);
136 static void     gtk_socket_grab_notify          (GtkWidget        *widget,
137                                                  gboolean          was_grabbed);
138 static gboolean gtk_socket_key_event            (GtkWidget        *widget,
139                                                  GdkEventKey      *event);
140 static gboolean gtk_socket_focus                (GtkWidget        *widget,
141                                                  GtkDirectionType  direction);
142 static void     gtk_socket_remove               (GtkContainer     *container,
143                                                  GtkWidget        *widget);
144 static void     gtk_socket_forall               (GtkContainer     *container,
145                                                  gboolean          include_internals,
146                                                  GtkCallback       callback,
147                                                  gpointer          callback_data);
148 static void     gtk_socket_add_window           (GtkSocket        *socket,
149                                                  Window            xid,
150                                                  gboolean          need_reparent);
151 static GdkFilterReturn gtk_socket_filter_func   (GdkXEvent        *gdk_xevent,
152                                                  GdkEvent         *event,
153                                                  gpointer          data);
154
155 static gboolean xembed_get_info                 (GdkWindow        *gdk_window,
156                                                  unsigned long    *version,
157                                                  unsigned long    *flags);
158
159 /* From Tk */
160 #define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
161
162
163 /* Local data */
164
165 typedef struct
166 {
167   guint                  accel_key;
168   GdkModifierType        accel_mods;
169 } GrabbedKey;
170
171 enum {
172   PLUG_ADDED,
173   PLUG_REMOVED,
174   LAST_SIGNAL
175 }; 
176
177 static guint socket_signals[LAST_SIGNAL] = { 0 };
178
179 G_DEFINE_TYPE (GtkSocket, gtk_socket, GTK_TYPE_CONTAINER)
180
181 static void
182 gtk_socket_finalize (GObject *object)
183 {
184   GtkSocket *socket = GTK_SOCKET (object);
185   GtkSocketPrivate *priv = socket->priv;
186
187   g_object_unref (priv->accel_group);
188
189   G_OBJECT_CLASS (gtk_socket_parent_class)->finalize (object);
190 }
191
192 static void
193 gtk_socket_class_init (GtkSocketClass *class)
194 {
195   GtkWidgetClass *widget_class;
196   GtkContainerClass *container_class;
197   GObjectClass *gobject_class;
198
199   gobject_class = (GObjectClass *) class;
200   widget_class = (GtkWidgetClass*) class;
201   container_class = (GtkContainerClass*) class;
202
203   gobject_class->finalize = gtk_socket_finalize;
204   gobject_class->notify = gtk_socket_notify;
205
206   widget_class->realize = gtk_socket_realize;
207   widget_class->unrealize = gtk_socket_unrealize;
208   widget_class->get_preferred_width = gtk_socket_get_preferred_width;
209   widget_class->get_preferred_height = gtk_socket_get_preferred_height;
210   widget_class->size_allocate = gtk_socket_size_allocate;
211   widget_class->hierarchy_changed = gtk_socket_hierarchy_changed;
212   widget_class->grab_notify = gtk_socket_grab_notify;
213   widget_class->key_press_event = gtk_socket_key_event;
214   widget_class->key_release_event = gtk_socket_key_event;
215   widget_class->focus = gtk_socket_focus;
216
217   /* We don't want to show_all the in-process plug, if any.
218    */
219   widget_class->show_all = gtk_widget_show;
220
221   container_class->remove = gtk_socket_remove;
222   container_class->forall = gtk_socket_forall;
223
224   /**
225    * GtkSocket::plug-added:
226    * @socket_: the object which received the signal
227    *
228    * This signal is emitted when a client is successfully
229    * added to the socket. 
230    */
231   socket_signals[PLUG_ADDED] =
232     g_signal_new (I_("plug-added"),
233                   G_OBJECT_CLASS_TYPE (class),
234                   G_SIGNAL_RUN_LAST,
235                   G_STRUCT_OFFSET (GtkSocketClass, plug_added),
236                   NULL, NULL,
237                   _gtk_marshal_VOID__VOID,
238                   G_TYPE_NONE, 0);
239
240   /**
241    * GtkSocket::plug-removed:
242    * @socket_: the object which received the signal
243    *
244    * This signal is emitted when a client is removed from the socket. 
245    * The default action is to destroy the #GtkSocket widget, so if you 
246    * want to reuse it you must add a signal handler that returns %TRUE. 
247    *
248    * Return value: %TRUE to stop other handlers from being invoked.
249    */
250   socket_signals[PLUG_REMOVED] =
251     g_signal_new (I_("plug-removed"),
252                   G_OBJECT_CLASS_TYPE (class),
253                   G_SIGNAL_RUN_LAST,
254                   G_STRUCT_OFFSET (GtkSocketClass, plug_removed),
255                   _gtk_boolean_handled_accumulator, NULL,
256                   _gtk_marshal_BOOLEAN__VOID,
257                   G_TYPE_BOOLEAN, 0);
258
259   g_type_class_add_private (gobject_class, sizeof (GtkSocketPrivate));
260 }
261
262 static void
263 gtk_socket_init (GtkSocket *socket)
264 {
265   GtkSocketPrivate *priv;
266
267   priv = G_TYPE_INSTANCE_GET_PRIVATE (socket,
268                                       GTK_TYPE_SOCKET,
269                                       GtkSocketPrivate);
270   socket->priv = priv;
271   priv->request_width = 0;
272   priv->request_height = 0;
273   priv->current_width = 0;
274   priv->current_height = 0;
275
276   priv->plug_window = NULL;
277   priv->plug_widget = NULL;
278   priv->focus_in = FALSE;
279   priv->have_size = FALSE;
280   priv->need_map = FALSE;
281   priv->active = FALSE;
282
283   priv->accel_group = gtk_accel_group_new ();
284   g_object_set_data (G_OBJECT (priv->accel_group), I_("gtk-socket"), socket);
285 }
286
287 /**
288  * gtk_socket_new:
289  * 
290  * Create a new empty #GtkSocket.
291  * 
292  * Return value:  the new #GtkSocket.
293  **/
294 GtkWidget*
295 gtk_socket_new (void)
296 {
297   GtkSocket *socket;
298
299   socket = g_object_new (GTK_TYPE_SOCKET, NULL);
300
301   return GTK_WIDGET (socket);
302 }
303
304 /**
305  * gtk_socket_add_id:
306  * @socket_: a #GtkSocket
307  * @window: the Window of a client participating in the XEMBED protocol.
308  *
309  * Adds an XEMBED client, such as a #GtkPlug, to the #GtkSocket.  The
310  * client may be in the same process or in a different process. 
311  * 
312  * To embed a #GtkPlug in a #GtkSocket, you can either create the
313  * #GtkPlug with <literal>gtk_plug_new (0)</literal>, call 
314  * gtk_plug_get_id() to get the window ID of the plug, and then pass that to the
315  * gtk_socket_add_id(), or you can call gtk_socket_get_id() to get the
316  * window ID for the socket, and call gtk_plug_new() passing in that
317  * ID.
318  *
319  * The #GtkSocket must have already be added into a toplevel window
320  *  before you can make this call.
321  **/
322 void           
323 gtk_socket_add_id (GtkSocket      *socket,
324                    Window          window)
325 {
326   g_return_if_fail (GTK_IS_SOCKET (socket));
327   g_return_if_fail (_gtk_widget_get_anchored (GTK_WIDGET (socket)));
328
329   if (!gtk_widget_get_realized (GTK_WIDGET (socket)))
330     gtk_widget_realize (GTK_WIDGET (socket));
331
332   gtk_socket_add_window (socket, window, TRUE);
333 }
334
335 /**
336  * gtk_socket_get_id:
337  * @socket_: a #GtkSocket.
338  * 
339  * Gets the window ID of a #GtkSocket widget, which can then
340  * be used to create a client embedded inside the socket, for
341  * instance with gtk_plug_new(). 
342  *
343  * The #GtkSocket must have already be added into a toplevel window 
344  * before you can make this call.
345  * 
346  * Return value: the window ID for the socket
347  **/
348 Window
349 gtk_socket_get_id (GtkSocket *socket)
350 {
351   g_return_val_if_fail (GTK_IS_SOCKET (socket), 0);
352   g_return_val_if_fail (_gtk_widget_get_anchored (GTK_WIDGET (socket)), 0);
353
354   if (!gtk_widget_get_realized (GTK_WIDGET (socket)))
355     gtk_widget_realize (GTK_WIDGET (socket));
356
357   return GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (socket)));
358 }
359
360 /**
361  * gtk_socket_get_plug_window:
362  * @socket_: a #GtkSocket.
363  *
364  * Retrieves the window of the plug. Use this to check if the plug has
365  * been created inside of the socket.
366  *
367  * Return value: (transfer none): the window of the plug if available, or %NULL
368  *
369  * Since:  2.14
370  **/
371 GdkWindow*
372 gtk_socket_get_plug_window (GtkSocket *socket)
373 {
374   g_return_val_if_fail (GTK_IS_SOCKET (socket), NULL);
375
376   return socket->priv->plug_window;
377 }
378
379 static void
380 gtk_socket_realize (GtkWidget *widget)
381 {
382   GtkAllocation allocation;
383   GtkSocket *socket = GTK_SOCKET (widget);
384   GdkWindow *window;
385   GdkWindowAttr attributes;
386   XWindowAttributes xattrs;
387   gint attributes_mask;
388
389   gtk_widget_set_realized (widget, TRUE);
390
391   gtk_widget_get_allocation (widget, &allocation);
392
393   attributes.window_type = GDK_WINDOW_CHILD;
394   attributes.x = allocation.x;
395   attributes.y = allocation.y;
396   attributes.width = allocation.width;
397   attributes.height = allocation.height;
398   attributes.wclass = GDK_INPUT_OUTPUT;
399   attributes.visual = gtk_widget_get_visual (widget);
400   attributes.event_mask = GDK_FOCUS_CHANGE_MASK;
401
402   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
403
404   window = gdk_window_new (gtk_widget_get_parent_window (widget),
405                            &attributes, attributes_mask);
406   gtk_widget_set_window (widget, window);
407   gdk_window_set_user_data (window, socket);
408
409   gtk_style_context_set_background (gtk_widget_get_style_context (widget),
410                                     window);
411
412   XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
413                         GDK_WINDOW_XID (window),
414                         &xattrs);
415
416   /* Sooooo, it turns out that mozilla, as per the gtk2xt code selects
417      for input on the socket with a mask of 0x0fffff (for god knows why)
418      which includes ButtonPressMask causing a BadAccess if someone else
419      also selects for this. As per the client-side windows merge we always
420      normally selects for button press so we can emulate it on client
421      side children that selects for button press. However, we don't need
422      this for GtkSocket, so we unselect it here, fixing the crashes in
423      firefox. */
424   XSelectInput (GDK_WINDOW_XDISPLAY (window),
425                 GDK_WINDOW_XID (window), 
426                 (xattrs.your_event_mask & ~ButtonPressMask) |
427                 SubstructureNotifyMask | SubstructureRedirectMask);
428
429   gdk_window_add_filter (window,
430                          gtk_socket_filter_func,
431                          widget);
432
433   /* We sync here so that we make sure that if the XID for
434    * our window is passed to another application, SubstructureRedirectMask
435    * will be set by the time the other app creates its window.
436    */
437   gdk_display_sync (gtk_widget_get_display (widget));
438 }
439
440 /**
441  * gtk_socket_end_embedding:
442  * @socket: a #GtkSocket
443  *
444  * Called to end the embedding of a plug in the socket.
445  */
446 static void
447 gtk_socket_end_embedding (GtkSocket *socket)
448 {
449   GtkSocketPrivate *private = socket->priv;
450
451   g_object_unref (private->plug_window);
452   private->plug_window = NULL;
453   private->current_width = 0;
454   private->current_height = 0;
455   private->resize_count = 0;
456
457   gtk_accel_group_disconnect (private->accel_group, NULL);
458 }
459
460 static void
461 gtk_socket_unrealize (GtkWidget *widget)
462 {
463   GtkSocket *socket = GTK_SOCKET (widget);
464   GtkSocketPrivate *private = socket->priv;
465
466   gtk_widget_set_realized (widget, FALSE);
467
468   if (private->plug_widget)
469     {
470       _gtk_plug_remove_from_socket (GTK_PLUG (private->plug_widget), socket);
471     }
472   else if (private->plug_window)
473     {
474       gtk_socket_end_embedding (socket);
475     }
476
477   GTK_WIDGET_CLASS (gtk_socket_parent_class)->unrealize (widget);
478 }
479
480 static void
481 gtk_socket_size_request (GtkSocket *socket)
482 {
483   GtkSocketPrivate *private = socket->priv;
484   XSizeHints hints;
485   long supplied;
486           
487   gdk_error_trap_push ();
488
489   private->request_width = 1;
490   private->request_height = 1;
491           
492   if (XGetWMNormalHints (GDK_WINDOW_XDISPLAY (private->plug_window),
493                          GDK_WINDOW_XID (private->plug_window),
494                          &hints, &supplied))
495     {
496       if (hints.flags & PMinSize)
497         {
498           private->request_width = MAX (hints.min_width, 1);
499           private->request_height = MAX (hints.min_height, 1);
500         }
501       else if (hints.flags & PBaseSize)
502         {
503           private->request_width = MAX (hints.base_width, 1);
504           private->request_height = MAX (hints.base_height, 1);
505         }
506     }
507   private->have_size = TRUE;
508   
509   gdk_error_trap_pop_ignored ();
510 }
511
512 static void
513 gtk_socket_get_preferred_width (GtkWidget *widget,
514                                 gint      *minimum,
515                                 gint      *natural)
516 {
517   GtkSocket *socket = GTK_SOCKET (widget);
518   GtkSocketPrivate *private = socket->priv;
519
520   if (private->plug_widget)
521     {
522       gtk_widget_get_preferred_width (private->plug_widget, minimum, natural);
523     }
524   else
525     {
526       if (private->is_mapped && !private->have_size && private->plug_window)
527         gtk_socket_size_request (socket);
528
529       if (private->is_mapped && private->have_size)
530         *minimum = *natural = MAX (private->request_width, 1);
531       else
532         *minimum = *natural = 1;
533     }
534 }
535
536 static void
537 gtk_socket_get_preferred_height (GtkWidget *widget,
538                                  gint      *minimum,
539                                  gint      *natural)
540 {
541   GtkSocket *socket = GTK_SOCKET (widget);
542   GtkSocketPrivate *private = socket->priv;
543
544   if (private->plug_widget)
545     {
546       gtk_widget_get_preferred_height (private->plug_widget, minimum, natural);
547     }
548   else
549     {
550       if (private->is_mapped && !private->have_size && private->plug_window)
551         gtk_socket_size_request (socket);
552
553       if (private->is_mapped && private->have_size)
554         *minimum = *natural = MAX (private->request_height, 1);
555       else
556         *minimum = *natural = 1;
557     }
558 }
559
560 static void
561 gtk_socket_send_configure_event (GtkSocket *socket)
562 {
563   GtkAllocation allocation;
564   XConfigureEvent xconfigure;
565   gint x, y;
566
567   g_return_if_fail (socket->priv->plug_window != NULL);
568
569   memset (&xconfigure, 0, sizeof (xconfigure));
570   xconfigure.type = ConfigureNotify;
571
572   xconfigure.event = GDK_WINDOW_XID (socket->priv->plug_window);
573   xconfigure.window = GDK_WINDOW_XID (socket->priv->plug_window);
574
575   /* The ICCCM says that synthetic events should have root relative
576    * coordinates. We still aren't really ICCCM compliant, since
577    * we don't send events when the real toplevel is moved.
578    */
579   gdk_error_trap_push ();
580   gdk_window_get_origin (socket->priv->plug_window, &x, &y);
581   gdk_error_trap_pop_ignored ();
582
583   gtk_widget_get_allocation (GTK_WIDGET(socket), &allocation);
584   xconfigure.x = x;
585   xconfigure.y = y;
586   xconfigure.width = allocation.width;
587   xconfigure.height = allocation.height;
588
589   xconfigure.border_width = 0;
590   xconfigure.above = None;
591   xconfigure.override_redirect = False;
592
593   gdk_error_trap_push ();
594   XSendEvent (GDK_WINDOW_XDISPLAY (socket->priv->plug_window),
595               GDK_WINDOW_XID (socket->priv->plug_window),
596               False, NoEventMask, (XEvent *)&xconfigure);
597   gdk_error_trap_pop_ignored ();
598 }
599
600 static void
601 gtk_socket_size_allocate (GtkWidget     *widget,
602                           GtkAllocation *allocation)
603 {
604   GtkSocket *socket = GTK_SOCKET (widget);
605   GtkSocketPrivate *private = socket->priv;
606
607   gtk_widget_set_allocation (widget, allocation);
608   if (gtk_widget_get_realized (widget))
609     {
610       gdk_window_move_resize (gtk_widget_get_window (widget),
611                               allocation->x, allocation->y,
612                               allocation->width, allocation->height);
613
614       if (private->plug_widget)
615         {
616           GtkAllocation child_allocation;
617
618           child_allocation.x = 0;
619           child_allocation.y = 0;
620           child_allocation.width = allocation->width;
621           child_allocation.height = allocation->height;
622
623           gtk_widget_size_allocate (private->plug_widget, &child_allocation);
624         }
625       else if (private->plug_window)
626         {
627           gdk_error_trap_push ();
628
629           if (allocation->width != private->current_width ||
630               allocation->height != private->current_height)
631             {
632               gdk_window_move_resize (private->plug_window,
633                                       0, 0,
634                                       allocation->width, allocation->height);
635               if (private->resize_count)
636                 private->resize_count--;
637               
638               GTK_NOTE (PLUGSOCKET,
639                         g_message ("GtkSocket - allocated: %d %d",
640                                    allocation->width, allocation->height));
641               private->current_width = allocation->width;
642               private->current_height = allocation->height;
643             }
644
645           if (private->need_map)
646             {
647               gdk_window_show (private->plug_window);
648               private->need_map = FALSE;
649             }
650
651           while (private->resize_count)
652             {
653               gtk_socket_send_configure_event (socket);
654               private->resize_count--;
655               GTK_NOTE (PLUGSOCKET,
656                         g_message ("GtkSocket - sending synthetic configure: %d %d",
657                                    allocation->width, allocation->height));
658             }
659
660           gdk_error_trap_pop_ignored ();
661         }
662     }
663 }
664
665 static void
666 gtk_socket_send_key_event (GtkSocket *socket,
667                            GdkEvent  *gdk_event,
668                            gboolean   mask_key_presses)
669 {
670   XKeyEvent xkey;
671   GdkScreen *screen = gdk_window_get_screen (socket->priv->plug_window);
672
673   memset (&xkey, 0, sizeof (xkey));
674   xkey.type = (gdk_event->type == GDK_KEY_PRESS) ? KeyPress : KeyRelease;
675   xkey.window = GDK_WINDOW_XID (socket->priv->plug_window);
676   xkey.root = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
677   xkey.subwindow = None;
678   xkey.time = gdk_event->key.time;
679   xkey.x = 0;
680   xkey.y = 0;
681   xkey.x_root = 0;
682   xkey.y_root = 0;
683   xkey.state = gdk_event->key.state;
684   xkey.keycode = gdk_event->key.hardware_keycode;
685   xkey.same_screen = True;/* FIXME ? */
686
687   gdk_error_trap_push ();
688   XSendEvent (GDK_WINDOW_XDISPLAY (socket->priv->plug_window),
689               GDK_WINDOW_XID (socket->priv->plug_window),
690               False,
691               (mask_key_presses ? KeyPressMask : NoEventMask),
692               (XEvent *)&xkey);
693   gdk_error_trap_pop_ignored ();
694 }
695
696 static gboolean
697 activate_key (GtkAccelGroup  *accel_group,
698               GObject        *acceleratable,
699               guint           accel_key,
700               GdkModifierType accel_mods,
701               GrabbedKey     *grabbed_key)
702 {
703   GdkEvent *gdk_event = gtk_get_current_event ();
704   
705   GtkSocket *socket = g_object_get_data (G_OBJECT (accel_group), "gtk-socket");
706   gboolean retval = FALSE;
707
708   if (gdk_event && gdk_event->type == GDK_KEY_PRESS && socket->priv->plug_window)
709     {
710       gtk_socket_send_key_event (socket, gdk_event, FALSE);
711       retval = TRUE;
712     }
713
714   if (gdk_event)
715     gdk_event_free (gdk_event);
716
717   return retval;
718 }
719
720 static gboolean
721 find_accel_key (GtkAccelKey *key,
722                 GClosure    *closure,
723                 gpointer     data)
724 {
725   GrabbedKey *grabbed_key = data;
726   
727   return (key->accel_key == grabbed_key->accel_key &&
728           key->accel_mods == grabbed_key->accel_mods);
729 }
730
731 /**
732  * gtk_socket_add_grabbed_key:
733  * @socket: a #GtkSocket
734  * @keyval: a key
735  * @modifiers: modifiers for the key
736  *
737  * Called from the GtkSocket platform-specific backend when the
738  * corresponding plug has told the socket to grab a key.
739  */
740 static void
741 gtk_socket_add_grabbed_key (GtkSocket       *socket,
742                             guint            keyval,
743                             GdkModifierType  modifiers)
744 {
745   GClosure *closure;
746   GrabbedKey *grabbed_key;
747
748   grabbed_key = g_new (GrabbedKey, 1);
749   
750   grabbed_key->accel_key = keyval;
751   grabbed_key->accel_mods = modifiers;
752
753   if (gtk_accel_group_find (socket->priv->accel_group,
754                             find_accel_key,
755                             &grabbed_key))
756     {
757       g_warning ("GtkSocket: request to add already present grabbed key %u,%#x\n",
758                  keyval, modifiers);
759       g_free (grabbed_key);
760       return;
761     }
762
763   closure = g_cclosure_new (G_CALLBACK (activate_key), grabbed_key, (GClosureNotify)g_free);
764
765   gtk_accel_group_connect (socket->priv->accel_group, keyval, modifiers, GTK_ACCEL_LOCKED,
766                            closure);
767 }
768
769 /**
770  * gtk_socket_remove_grabbed_key:
771  * @socket: a #GtkSocket
772  * @keyval: a key
773  * @modifiers: modifiers for the key
774  *
775  * Called from the GtkSocket backend when the corresponding plug has
776  * told the socket to remove a key grab.
777  */
778 static void
779 gtk_socket_remove_grabbed_key (GtkSocket      *socket,
780                                guint           keyval,
781                                GdkModifierType modifiers)
782 {
783   if (!gtk_accel_group_disconnect_key (socket->priv->accel_group, keyval, modifiers))
784     g_warning ("GtkSocket: request to remove non-present grabbed key %u,%#x\n",
785                keyval, modifiers);
786 }
787
788 static void
789 socket_update_focus_in (GtkSocket *socket)
790 {
791   GtkSocketPrivate *private = socket->priv;
792   gboolean focus_in = FALSE;
793
794   if (private->plug_window)
795     {
796       GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
797
798       if (gtk_widget_is_toplevel (toplevel) &&
799           gtk_window_has_toplevel_focus (GTK_WINDOW (toplevel)) &&
800           gtk_widget_is_focus (GTK_WIDGET (socket)))
801         focus_in = TRUE;
802     }
803
804   if (focus_in != private->focus_in)
805     {
806       private->focus_in = focus_in;
807
808       if (focus_in)
809         _gtk_xembed_send_focus_message (private->plug_window,
810                                         XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
811       else
812         _gtk_xembed_send_message (private->plug_window,
813                                   XEMBED_FOCUS_OUT, 0, 0, 0);
814     }
815 }
816
817 static void
818 socket_update_active (GtkSocket *socket)
819 {
820   GtkSocketPrivate *private = socket->priv;
821   gboolean active = FALSE;
822
823   if (private->plug_window)
824     {
825       GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
826
827       if (gtk_widget_is_toplevel (toplevel) &&
828           gtk_window_is_active  (GTK_WINDOW (toplevel)))
829         active = TRUE;
830     }
831
832   if (active != private->active)
833     {
834       private->active = active;
835
836       _gtk_xembed_send_message (private->plug_window,
837                                 active ? XEMBED_WINDOW_ACTIVATE : XEMBED_WINDOW_DEACTIVATE,
838                                 0, 0, 0);
839     }
840 }
841
842 static void
843 gtk_socket_hierarchy_changed (GtkWidget *widget,
844                               GtkWidget *old_toplevel)
845 {
846   GtkSocket *socket = GTK_SOCKET (widget);
847   GtkSocketPrivate *private = socket->priv;
848   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
849
850   if (toplevel && !GTK_IS_WINDOW (toplevel))
851     toplevel = NULL;
852
853   if (toplevel != private->toplevel)
854     {
855       if (private->toplevel)
856         {
857           gtk_window_remove_accel_group (GTK_WINDOW (private->toplevel), private->accel_group);
858           g_signal_handlers_disconnect_by_func (private->toplevel,
859                                                 socket_update_focus_in,
860                                                 socket);
861           g_signal_handlers_disconnect_by_func (private->toplevel,
862                                                 socket_update_active,
863                                                 socket);
864         }
865
866       private->toplevel = toplevel;
867
868       if (toplevel)
869         {
870           gtk_window_add_accel_group (GTK_WINDOW (private->toplevel), private->accel_group);
871           g_signal_connect_swapped (private->toplevel, "notify::has-toplevel-focus",
872                                     G_CALLBACK (socket_update_focus_in), socket);
873           g_signal_connect_swapped (private->toplevel, "notify::is-active",
874                                     G_CALLBACK (socket_update_active), socket);
875         }
876
877       socket_update_focus_in (socket);
878       socket_update_active (socket);
879     }
880 }
881
882 static void
883 gtk_socket_grab_notify (GtkWidget *widget,
884                         gboolean   was_grabbed)
885 {
886   GtkSocket *socket = GTK_SOCKET (widget);
887
888   if (!socket->priv->same_app)
889     _gtk_xembed_send_message (socket->priv->plug_window,
890                               was_grabbed ? XEMBED_MODALITY_OFF : XEMBED_MODALITY_ON,
891                               0, 0, 0);
892 }
893
894 static gboolean
895 gtk_socket_key_event (GtkWidget   *widget,
896                       GdkEventKey *event)
897 {
898   GtkSocket *socket = GTK_SOCKET (widget);
899   GtkSocketPrivate *private = socket->priv;
900   
901   if (gtk_widget_has_focus (widget) && private->plug_window && !private->plug_widget)
902     {
903       gtk_socket_send_key_event (socket, (GdkEvent *) event, FALSE);
904
905       return TRUE;
906     }
907   else
908     return FALSE;
909 }
910
911 static void
912 gtk_socket_notify (GObject    *object,
913                    GParamSpec *pspec)
914 {
915   if (strcmp (pspec->name, "is-focus") == 0)
916     socket_update_focus_in (GTK_SOCKET (object));
917
918   if (G_OBJECT_CLASS (gtk_socket_parent_class)->notify)
919     G_OBJECT_CLASS (gtk_socket_parent_class)->notify (object, pspec);
920 }
921
922 /**
923  * gtk_socket_claim_focus:
924  * @socket: a #GtkSocket
925  * @send_event: huh?
926  *
927  * Claims focus for the socket. XXX send_event?
928  */
929 static void
930 gtk_socket_claim_focus (GtkSocket *socket,
931                         gboolean   send_event)
932 {
933   GtkWidget *widget = GTK_WIDGET (socket);
934   GtkSocketPrivate *private = socket->priv;
935
936   if (!send_event)
937     private->focus_in = TRUE;   /* Otherwise, our notify handler will send FOCUS_IN  */
938       
939   /* Oh, the trickery... */
940   
941   gtk_widget_set_can_focus (widget, TRUE);
942   gtk_widget_grab_focus (widget);
943   gtk_widget_set_can_focus (widget, FALSE);
944 }
945
946 static gboolean
947 gtk_socket_focus (GtkWidget       *widget,
948                   GtkDirectionType direction)
949 {
950   GtkSocket *socket = GTK_SOCKET (widget);
951   GtkSocketPrivate *private = socket->priv;
952
953   if (private->plug_widget)
954     return gtk_widget_child_focus (private->plug_widget, direction);
955
956   if (!gtk_widget_is_focus (widget))
957     {
958       gint detail = -1;
959
960       switch (direction)
961         {
962         case GTK_DIR_UP:
963         case GTK_DIR_LEFT:
964         case GTK_DIR_TAB_BACKWARD:
965           detail = XEMBED_FOCUS_LAST;
966           break;
967         case GTK_DIR_DOWN:
968         case GTK_DIR_RIGHT:
969         case GTK_DIR_TAB_FORWARD:
970           detail = XEMBED_FOCUS_FIRST;
971           break;
972         }
973       
974       _gtk_xembed_send_focus_message (private->plug_window, XEMBED_FOCUS_IN, detail);
975       gtk_socket_claim_focus (socket, FALSE);
976  
977       return TRUE;
978     }
979   else
980     return FALSE;
981 }
982
983 static void
984 gtk_socket_remove (GtkContainer *container,
985                    GtkWidget    *child)
986 {
987   GtkSocket *socket = GTK_SOCKET (container);
988   GtkSocketPrivate *private = socket->priv;
989
990   g_return_if_fail (child == private->plug_widget);
991
992   _gtk_plug_remove_from_socket (GTK_PLUG (private->plug_widget), socket);
993 }
994
995 static void
996 gtk_socket_forall (GtkContainer *container,
997                    gboolean      include_internals,
998                    GtkCallback   callback,
999                    gpointer      callback_data)
1000 {
1001   GtkSocket *socket = GTK_SOCKET (container);
1002   GtkSocketPrivate *private = socket->priv;
1003
1004   if (private->plug_widget)
1005     (* callback) (private->plug_widget, callback_data);
1006 }
1007
1008 /**
1009  * gtk_socket_add_window:
1010  * @socket: a #GtkSocket
1011  * @xid: the native identifier for a window
1012  * @need_reparent: whether the socket's plug's window needs to be
1013  *                 reparented to the socket
1014  *
1015  * Adds a window to a GtkSocket.
1016  */
1017 static void
1018 gtk_socket_add_window (GtkSocket       *socket,
1019                        Window           xid,
1020                        gboolean         need_reparent)
1021 {
1022   GtkWidget *widget = GTK_WIDGET (socket);
1023   GdkDisplay *display = gtk_widget_get_display (widget);
1024   gpointer user_data = NULL;
1025   GtkSocketPrivate *private = socket->priv;
1026   unsigned long version;
1027   unsigned long flags;
1028
1029   if (GDK_IS_X11_DISPLAY (display))
1030     private->plug_window = gdk_x11_window_lookup_for_display (display, xid);
1031   else
1032     private->plug_window = NULL;
1033
1034   if (private->plug_window)
1035     {
1036       g_object_ref (private->plug_window);
1037       gdk_window_get_user_data (private->plug_window, &user_data);
1038     }
1039
1040   if (user_data) /* A widget's window in this process */
1041     {
1042       GtkWidget *child_widget = user_data;
1043
1044       if (!GTK_IS_PLUG (child_widget))
1045         {
1046           g_warning (G_STRLOC ": Can't add non-GtkPlug to GtkSocket");
1047           private->plug_window = NULL;
1048           gdk_error_trap_pop_ignored ();
1049
1050           return;
1051         }
1052
1053       _gtk_plug_add_to_socket (GTK_PLUG (child_widget), socket);
1054     }
1055   else  /* A foreign window */
1056     {
1057       GdkDragProtocol protocol;
1058
1059       gdk_error_trap_push ();
1060
1061       if (!private->plug_window)
1062         {
1063           if (GDK_IS_X11_DISPLAY (display))
1064             private->plug_window = gdk_x11_window_foreign_new_for_display (display, xid);
1065           if (!private->plug_window) /* was deleted before we could get it */
1066             {
1067               gdk_error_trap_pop_ignored ();
1068               return;
1069             }
1070         }
1071
1072       XSelectInput (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (socket))),
1073                     GDK_WINDOW_XID (private->plug_window),
1074                     StructureNotifyMask | PropertyChangeMask);
1075
1076       if (gdk_error_trap_pop ())
1077         {
1078           g_object_unref (private->plug_window);
1079           private->plug_window = NULL;
1080           return;
1081         }
1082       
1083       /* OK, we now will reliably get destroy notification on socket->plug_window */
1084
1085       gdk_error_trap_push ();
1086
1087       if (need_reparent)
1088         {
1089           gdk_window_hide (private->plug_window); /* Shouldn't actually be necessary for XEMBED, but just in case */
1090           gdk_window_reparent (private->plug_window,
1091                                gtk_widget_get_window (widget),
1092                                0, 0);
1093         }
1094
1095       private->have_size = FALSE;
1096
1097       private->xembed_version = -1;
1098       if (xembed_get_info (private->plug_window, &version, &flags))
1099         {
1100           private->xembed_version = MIN (GTK_XEMBED_PROTOCOL_VERSION, version);
1101           private->is_mapped = (flags & XEMBED_MAPPED) != 0;
1102         }
1103       else
1104         {
1105           /* FIXME, we should probably actually check the state before we started */
1106           private->is_mapped = TRUE;
1107         }
1108
1109       private->need_map = private->is_mapped;
1110
1111       protocol = gdk_window_get_drag_protocol (private->plug_window, NULL);
1112       if (protocol)
1113         gtk_drag_dest_set_proxy (GTK_WIDGET (socket), private->plug_window,
1114                                  protocol, TRUE);
1115
1116       gdk_error_trap_pop_ignored ();
1117
1118       gdk_window_add_filter (private->plug_window,
1119                              gtk_socket_filter_func,
1120                              socket);
1121
1122 #ifdef HAVE_XFIXES
1123       gdk_error_trap_push ();
1124       XFixesChangeSaveSet (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (socket))),
1125                            GDK_WINDOW_XID (private->plug_window),
1126                            SetModeInsert, SaveSetRoot, SaveSetUnmap);
1127       gdk_error_trap_pop_ignored ();
1128 #endif
1129       _gtk_xembed_send_message (private->plug_window,
1130                                 XEMBED_EMBEDDED_NOTIFY, 0,
1131                                 GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (socket))),
1132                                 private->xembed_version);
1133
1134       socket_update_active (socket);
1135       socket_update_focus_in (socket);
1136
1137       gtk_widget_queue_resize (GTK_WIDGET (socket));
1138     }
1139
1140   if (private->plug_window)
1141     g_signal_emit (socket, socket_signals[PLUG_ADDED], 0);
1142 }
1143
1144 /**
1145  * gtk_socket_handle_map_request:
1146  * @socket: a #GtkSocket
1147  *
1148  * Called from the GtkSocket backend when the plug has been mapped.
1149  */
1150 static void
1151 gtk_socket_handle_map_request (GtkSocket *socket)
1152 {
1153   GtkSocketPrivate *private = socket->priv;
1154   if (!private->is_mapped)
1155     {
1156       private->is_mapped = TRUE;
1157       private->need_map = TRUE;
1158
1159       gtk_widget_queue_resize (GTK_WIDGET (socket));
1160     }
1161 }
1162
1163 /**
1164  * gtk_socket_unmap_notify:
1165  * @socket: a #GtkSocket
1166  *
1167  * Called from the GtkSocket backend when the plug has been unmapped ???
1168  */
1169 static void
1170 gtk_socket_unmap_notify (GtkSocket *socket)
1171 {
1172   GtkSocketPrivate *private = socket->priv;
1173   if (private->is_mapped)
1174     {
1175       private->is_mapped = FALSE;
1176       gtk_widget_queue_resize (GTK_WIDGET (socket));
1177     }
1178 }
1179
1180 /**
1181  * gtk_socket_advance_toplevel_focus:
1182  * @socket: a #GtkSocket
1183  * @direction: a direction
1184  *
1185  * Called from the GtkSocket backend when the corresponding plug
1186  * has told the socket to move the focus.
1187  */
1188 static void
1189 gtk_socket_advance_toplevel_focus (GtkSocket        *socket,
1190                                    GtkDirectionType  direction)
1191 {
1192   GtkBin *bin;
1193   GtkWindow *window;
1194   GtkContainer *container;
1195   GtkWidget *child;
1196   GtkWidget *focus_widget;
1197   GtkWidget *toplevel;
1198   GtkWidget *old_focus_child;
1199   GtkWidget *parent;
1200
1201   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
1202   if (!toplevel)
1203     return;
1204
1205   if (!gtk_widget_is_toplevel (toplevel) || GTK_IS_PLUG (toplevel))
1206     {
1207       gtk_widget_child_focus (toplevel,direction);
1208       return;
1209     }
1210
1211   container = GTK_CONTAINER (toplevel);
1212   window = GTK_WINDOW (toplevel);
1213   bin = GTK_BIN (toplevel);
1214
1215   /* This is a copy of gtk_window_focus(), modified so that we
1216    * can detect wrap-around.
1217    */
1218   old_focus_child = gtk_container_get_focus_child (container);
1219   
1220   if (old_focus_child)
1221     {
1222       if (gtk_widget_child_focus (old_focus_child, direction))
1223         return;
1224
1225       /* We are allowed exactly one wrap-around per sequence of focus
1226        * events
1227        */
1228       if (_gtk_xembed_get_focus_wrapped ())
1229         return;
1230       else
1231         _gtk_xembed_set_focus_wrapped ();
1232     }
1233
1234   focus_widget = gtk_window_get_focus (window);
1235   if (window)
1236     {
1237       /* Wrapped off the end, clear the focus setting for the toplevel */
1238       parent = gtk_widget_get_parent (focus_widget);
1239       while (parent)
1240         {
1241           gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
1242           parent = gtk_widget_get_parent (parent);
1243         }
1244       
1245       gtk_window_set_focus (GTK_WINDOW (container), NULL);
1246     }
1247
1248   /* Now try to focus the first widget in the window */
1249   child = gtk_bin_get_child (bin);
1250   if (child)
1251     {
1252       if (gtk_widget_child_focus (child, direction))
1253         return;
1254     }
1255 }
1256
1257 static gboolean
1258 xembed_get_info (GdkWindow     *window,
1259                  unsigned long *version,
1260                  unsigned long *flags)
1261 {
1262   GdkDisplay *display = gdk_window_get_display (window);
1263   Atom xembed_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO");
1264   Atom type;
1265   int format;
1266   unsigned long nitems, bytes_after;
1267   unsigned char *data;
1268   unsigned long *data_long;
1269   int status;
1270   
1271   gdk_error_trap_push ();
1272   status = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
1273                                GDK_WINDOW_XID (window),
1274                                xembed_info_atom,
1275                                0, 2, False,
1276                                xembed_info_atom, &type, &format,
1277                                &nitems, &bytes_after, &data);
1278   gdk_error_trap_pop_ignored ();
1279
1280   if (status != Success)
1281     return FALSE;               /* Window vanished? */
1282
1283   if (type == None)             /* No info property */
1284     return FALSE;
1285
1286   if (type != xembed_info_atom)
1287     {
1288       g_warning ("_XEMBED_INFO property has wrong type\n");
1289       return FALSE;
1290     }
1291   
1292   if (nitems < 2)
1293     {
1294       g_warning ("_XEMBED_INFO too short\n");
1295       XFree (data);
1296       return FALSE;
1297     }
1298   
1299   data_long = (unsigned long *)data;
1300   if (version)
1301     *version = data_long[0];
1302   if (flags)
1303     *flags = data_long[1] & XEMBED_MAPPED;
1304   
1305   XFree (data);
1306   return TRUE;
1307 }
1308
1309 static void
1310 handle_xembed_message (GtkSocket        *socket,
1311                        XEmbedMessageType message,
1312                        glong             detail,
1313                        glong             data1,
1314                        glong             data2,
1315                        guint32           time)
1316 {
1317   GTK_NOTE (PLUGSOCKET,
1318             g_message ("GtkSocket: %s received", _gtk_xembed_message_name (message)));
1319   
1320   switch (message)
1321     {
1322     case XEMBED_EMBEDDED_NOTIFY:
1323     case XEMBED_WINDOW_ACTIVATE:
1324     case XEMBED_WINDOW_DEACTIVATE:
1325     case XEMBED_MODALITY_ON:
1326     case XEMBED_MODALITY_OFF:
1327     case XEMBED_FOCUS_IN:
1328     case XEMBED_FOCUS_OUT:
1329       g_warning ("GtkSocket: Invalid _XEMBED message %s received", _gtk_xembed_message_name (message));
1330       break;
1331       
1332     case XEMBED_REQUEST_FOCUS:
1333       gtk_socket_claim_focus (socket, TRUE);
1334       break;
1335
1336     case XEMBED_FOCUS_NEXT:
1337     case XEMBED_FOCUS_PREV:
1338       gtk_socket_advance_toplevel_focus (socket,
1339                                          (message == XEMBED_FOCUS_NEXT ?
1340                                           GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD));
1341       break;
1342       
1343     case XEMBED_GTK_GRAB_KEY:
1344       gtk_socket_add_grabbed_key (socket, data1, data2);
1345       break; 
1346     case XEMBED_GTK_UNGRAB_KEY:
1347       gtk_socket_remove_grabbed_key (socket, data1, data2);
1348       break;
1349
1350     case XEMBED_GRAB_KEY:
1351     case XEMBED_UNGRAB_KEY:
1352       break;
1353       
1354     default:
1355       GTK_NOTE (PLUGSOCKET,
1356                 g_message ("GtkSocket: Ignoring unknown _XEMBED message of type %d", message));
1357       break;
1358     }
1359 }
1360
1361 static GdkFilterReturn
1362 gtk_socket_filter_func (GdkXEvent *gdk_xevent,
1363                         GdkEvent  *event,
1364                         gpointer   data)
1365 {
1366   GtkSocket *socket;
1367   GtkWidget *widget;
1368   GdkDisplay *display;
1369   XEvent *xevent;
1370   GtkSocketPrivate *private;
1371
1372   GdkFilterReturn return_val;
1373
1374   socket = GTK_SOCKET (data);
1375   private = socket->priv;
1376
1377   return_val = GDK_FILTER_CONTINUE;
1378
1379   if (private->plug_widget)
1380     return return_val;
1381
1382   widget = GTK_WIDGET (socket);
1383   xevent = (XEvent *)gdk_xevent;
1384   display = gtk_widget_get_display (widget);
1385
1386   switch (xevent->type)
1387     {
1388     case ClientMessage:
1389       if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED"))
1390         {
1391           _gtk_xembed_push_message (xevent);
1392           handle_xembed_message (socket,
1393                                  xevent->xclient.data.l[1],
1394                                  xevent->xclient.data.l[2],
1395                                  xevent->xclient.data.l[3],
1396                                  xevent->xclient.data.l[4],
1397                                  xevent->xclient.data.l[0]);
1398           _gtk_xembed_pop_message ();
1399           
1400           return_val = GDK_FILTER_REMOVE;
1401         }
1402       break;
1403
1404     case CreateNotify:
1405       {
1406         XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
1407
1408         if (!private->plug_window)
1409           {
1410             gtk_socket_add_window (socket, xcwe->window, FALSE);
1411
1412             if (private->plug_window)
1413               {
1414                 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window created"));
1415               }
1416           }
1417         
1418         return_val = GDK_FILTER_REMOVE;
1419         
1420         break;
1421       }
1422
1423     case ConfigureRequest:
1424       {
1425         XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
1426         
1427         if (!private->plug_window)
1428           gtk_socket_add_window (socket, xcre->window, FALSE);
1429         
1430         if (private->plug_window)
1431           {
1432             if (xcre->value_mask & (CWWidth | CWHeight))
1433               {
1434                 GTK_NOTE (PLUGSOCKET,
1435                           g_message ("GtkSocket - configure request: %d %d",
1436                                      private->request_width,
1437                                      private->request_height));
1438
1439                 private->resize_count++;
1440                 gtk_widget_queue_resize (widget);
1441               }
1442             else if (xcre->value_mask & (CWX | CWY))
1443               {
1444                 gtk_socket_send_configure_event (socket);
1445               }
1446             /* Ignore stacking requests. */
1447             
1448             return_val = GDK_FILTER_REMOVE;
1449           }
1450         break;
1451       }
1452
1453     case DestroyNotify:
1454       {
1455         XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
1456
1457         /* Note that we get destroy notifies both from SubstructureNotify on
1458          * our window and StructureNotify on socket->plug_window
1459          */
1460         if (private->plug_window && (xdwe->window == GDK_WINDOW_XID (private->plug_window)))
1461           {
1462             gboolean result;
1463             
1464             GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - destroy notify"));
1465             
1466             gdk_window_destroy_notify (private->plug_window);
1467             gtk_socket_end_embedding (socket);
1468
1469             g_object_ref (widget);
1470             g_signal_emit_by_name (widget, "plug-removed", &result);
1471             if (!result)
1472               gtk_widget_destroy (widget);
1473             g_object_unref (widget);
1474             
1475             return_val = GDK_FILTER_REMOVE;
1476           }
1477         break;
1478       }
1479
1480     case FocusIn:
1481       if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
1482         {
1483           gtk_socket_claim_focus (socket, TRUE);
1484         }
1485       return_val = GDK_FILTER_REMOVE;
1486       break;
1487     case FocusOut:
1488       return_val = GDK_FILTER_REMOVE;
1489       break;
1490     case MapRequest:
1491       if (!private->plug_window)
1492         {
1493           gtk_socket_add_window (socket, xevent->xmaprequest.window, FALSE);
1494         }
1495         
1496       if (private->plug_window)
1497         {
1498           GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Map Request"));
1499
1500           gtk_socket_handle_map_request (socket);
1501           return_val = GDK_FILTER_REMOVE;
1502         }
1503       break;
1504     case PropertyNotify:
1505       if (private->plug_window &&
1506           xevent->xproperty.window == GDK_WINDOW_XID (private->plug_window))
1507         {
1508           GdkDragProtocol protocol;
1509
1510           if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_NORMAL_HINTS"))
1511             {
1512               GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - received PropertyNotify for plug's WM_NORMAL_HINTS"));
1513               private->have_size = FALSE;
1514               gtk_widget_queue_resize (widget);
1515               return_val = GDK_FILTER_REMOVE;
1516             }
1517           else if ((xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndAware")) ||
1518               (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO")))
1519             {
1520               gdk_error_trap_push ();
1521               protocol = gdk_window_get_drag_protocol (private->plug_window, NULL);
1522               if (protocol)
1523                 gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
1524                                          private->plug_window,
1525                                          protocol, TRUE);
1526
1527               gdk_error_trap_pop_ignored ();
1528               return_val = GDK_FILTER_REMOVE;
1529             }
1530           else if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO"))
1531             {
1532               unsigned long flags;
1533               
1534               if (xembed_get_info (private->plug_window, NULL, &flags))
1535                 {
1536                   gboolean was_mapped = private->is_mapped;
1537                   gboolean is_mapped = (flags & XEMBED_MAPPED) != 0;
1538
1539                   if (was_mapped != is_mapped)
1540                     {
1541                       if (is_mapped)
1542                         gtk_socket_handle_map_request (socket);
1543                       else
1544                         {
1545                           gdk_error_trap_push ();
1546                           gdk_window_show (private->plug_window);
1547                           gdk_error_trap_pop_ignored ();
1548                           
1549                           gtk_socket_unmap_notify (socket);
1550                         }
1551                     }
1552                 }
1553               return_val = GDK_FILTER_REMOVE;
1554             }
1555         }
1556       break;
1557     case ReparentNotify:
1558       {
1559         GdkWindow *window;
1560         XReparentEvent *xre = &xevent->xreparent;
1561
1562         window = gtk_widget_get_window (widget);
1563
1564         GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - ReparentNotify received"));
1565         if (!private->plug_window &&
1566             xre->parent == GDK_WINDOW_XID (window))
1567           {
1568             gtk_socket_add_window (socket, xre->window, FALSE);
1569             
1570             if (private->plug_window)
1571               {
1572                 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window reparented"));
1573               }
1574             
1575             return_val = GDK_FILTER_REMOVE;
1576           }
1577         else
1578           {
1579             if (private->plug_window &&
1580                 xre->window == GDK_WINDOW_XID (private->plug_window) &&
1581                 xre->parent != GDK_WINDOW_XID (window))
1582               {
1583                 gboolean result;
1584
1585                 gtk_socket_end_embedding (socket);
1586
1587                 g_object_ref (widget);
1588                 g_signal_emit_by_name (widget, "plug-removed", &result);
1589                 if (!result)
1590                   gtk_widget_destroy (widget);
1591                 g_object_unref (widget);
1592
1593                 return_val = GDK_FILTER_REMOVE;
1594               }
1595           }
1596
1597         break;
1598       }
1599     case UnmapNotify:
1600       if (private->plug_window &&
1601           xevent->xunmap.window == GDK_WINDOW_XID (private->plug_window))
1602         {
1603           GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Unmap notify"));
1604
1605           gtk_socket_unmap_notify (socket);
1606           return_val = GDK_FILTER_REMOVE;
1607         }
1608       break;
1609       
1610     }
1611   
1612   return return_val;
1613 }