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