]> Pileus Git - ~andy/gtk/blob - gtk/gtksocket.c
stylecontext: Do invalidation on first resize container
[~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   GdkWindow *window;
384   GdkWindowAttr attributes;
385   XWindowAttributes xattrs;
386   gint attributes_mask;
387
388   gtk_widget_set_realized (widget, TRUE);
389
390   gtk_widget_get_allocation (widget, &allocation);
391
392   attributes.window_type = GDK_WINDOW_CHILD;
393   attributes.x = allocation.x;
394   attributes.y = allocation.y;
395   attributes.width = allocation.width;
396   attributes.height = allocation.height;
397   attributes.wclass = GDK_INPUT_OUTPUT;
398   attributes.visual = gtk_widget_get_visual (widget);
399   attributes.event_mask = GDK_FOCUS_CHANGE_MASK;
400
401   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
402
403   window = gdk_window_new (gtk_widget_get_parent_window (widget),
404                            &attributes, attributes_mask);
405   gtk_widget_set_window (widget, window);
406   gtk_widget_register_window (widget, window);
407
408   gtk_style_context_set_background (gtk_widget_get_style_context (widget),
409                                     window);
410
411   XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
412                         GDK_WINDOW_XID (window),
413                         &xattrs);
414
415   /* Sooooo, it turns out that mozilla, as per the gtk2xt code selects
416      for input on the socket with a mask of 0x0fffff (for god knows why)
417      which includes ButtonPressMask causing a BadAccess if someone else
418      also selects for this. As per the client-side windows merge we always
419      normally selects for button press so we can emulate it on client
420      side children that selects for button press. However, we don't need
421      this for GtkSocket, so we unselect it here, fixing the crashes in
422      firefox. */
423   XSelectInput (GDK_WINDOW_XDISPLAY (window),
424                 GDK_WINDOW_XID (window), 
425                 (xattrs.your_event_mask & ~ButtonPressMask) |
426                 SubstructureNotifyMask | SubstructureRedirectMask);
427
428   gdk_window_add_filter (window,
429                          gtk_socket_filter_func,
430                          widget);
431
432   /* We sync here so that we make sure that if the XID for
433    * our window is passed to another application, SubstructureRedirectMask
434    * will be set by the time the other app creates its window.
435    */
436   gdk_display_sync (gtk_widget_get_display (widget));
437 }
438
439 /**
440  * gtk_socket_end_embedding:
441  * @socket: a #GtkSocket
442  *
443  * Called to end the embedding of a plug in the socket.
444  */
445 static void
446 gtk_socket_end_embedding (GtkSocket *socket)
447 {
448   GtkSocketPrivate *private = socket->priv;
449
450   g_object_unref (private->plug_window);
451   private->plug_window = NULL;
452   private->current_width = 0;
453   private->current_height = 0;
454   private->resize_count = 0;
455
456   gtk_accel_group_disconnect (private->accel_group, NULL);
457 }
458
459 static void
460 gtk_socket_unrealize (GtkWidget *widget)
461 {
462   GtkSocket *socket = GTK_SOCKET (widget);
463   GtkSocketPrivate *private = socket->priv;
464
465   gtk_widget_set_realized (widget, FALSE);
466
467   if (private->plug_widget)
468     {
469       _gtk_plug_remove_from_socket (GTK_PLUG (private->plug_widget), socket);
470     }
471   else if (private->plug_window)
472     {
473       gtk_socket_end_embedding (socket);
474     }
475
476   GTK_WIDGET_CLASS (gtk_socket_parent_class)->unrealize (widget);
477 }
478
479 static void
480 gtk_socket_size_request (GtkSocket *socket)
481 {
482   GtkSocketPrivate *private = socket->priv;
483   XSizeHints hints;
484   long supplied;
485           
486   gdk_error_trap_push ();
487
488   private->request_width = 1;
489   private->request_height = 1;
490           
491   if (XGetWMNormalHints (GDK_WINDOW_XDISPLAY (private->plug_window),
492                          GDK_WINDOW_XID (private->plug_window),
493                          &hints, &supplied))
494     {
495       if (hints.flags & PMinSize)
496         {
497           private->request_width = MAX (hints.min_width, 1);
498           private->request_height = MAX (hints.min_height, 1);
499         }
500       else if (hints.flags & PBaseSize)
501         {
502           private->request_width = MAX (hints.base_width, 1);
503           private->request_height = MAX (hints.base_height, 1);
504         }
505     }
506   private->have_size = TRUE;
507   
508   gdk_error_trap_pop_ignored ();
509 }
510
511 static void
512 gtk_socket_get_preferred_width (GtkWidget *widget,
513                                 gint      *minimum,
514                                 gint      *natural)
515 {
516   GtkSocket *socket = GTK_SOCKET (widget);
517   GtkSocketPrivate *private = socket->priv;
518
519   if (private->plug_widget)
520     {
521       gtk_widget_get_preferred_width (private->plug_widget, minimum, natural);
522     }
523   else
524     {
525       if (private->is_mapped && !private->have_size && private->plug_window)
526         gtk_socket_size_request (socket);
527
528       if (private->is_mapped && private->have_size)
529         *minimum = *natural = MAX (private->request_width, 1);
530       else
531         *minimum = *natural = 1;
532     }
533 }
534
535 static void
536 gtk_socket_get_preferred_height (GtkWidget *widget,
537                                  gint      *minimum,
538                                  gint      *natural)
539 {
540   GtkSocket *socket = GTK_SOCKET (widget);
541   GtkSocketPrivate *private = socket->priv;
542
543   if (private->plug_widget)
544     {
545       gtk_widget_get_preferred_height (private->plug_widget, minimum, natural);
546     }
547   else
548     {
549       if (private->is_mapped && !private->have_size && private->plug_window)
550         gtk_socket_size_request (socket);
551
552       if (private->is_mapped && private->have_size)
553         *minimum = *natural = MAX (private->request_height, 1);
554       else
555         *minimum = *natural = 1;
556     }
557 }
558
559 static void
560 gtk_socket_send_configure_event (GtkSocket *socket)
561 {
562   GtkAllocation allocation;
563   XConfigureEvent xconfigure;
564   gint x, y;
565
566   g_return_if_fail (socket->priv->plug_window != NULL);
567
568   memset (&xconfigure, 0, sizeof (xconfigure));
569   xconfigure.type = ConfigureNotify;
570
571   xconfigure.event = GDK_WINDOW_XID (socket->priv->plug_window);
572   xconfigure.window = GDK_WINDOW_XID (socket->priv->plug_window);
573
574   /* The ICCCM says that synthetic events should have root relative
575    * coordinates. We still aren't really ICCCM compliant, since
576    * we don't send events when the real toplevel is moved.
577    */
578   gdk_error_trap_push ();
579   gdk_window_get_origin (socket->priv->plug_window, &x, &y);
580   gdk_error_trap_pop_ignored ();
581
582   gtk_widget_get_allocation (GTK_WIDGET(socket), &allocation);
583   xconfigure.x = x;
584   xconfigure.y = y;
585   xconfigure.width = allocation.width;
586   xconfigure.height = allocation.height;
587
588   xconfigure.border_width = 0;
589   xconfigure.above = None;
590   xconfigure.override_redirect = False;
591
592   gdk_error_trap_push ();
593   XSendEvent (GDK_WINDOW_XDISPLAY (socket->priv->plug_window),
594               GDK_WINDOW_XID (socket->priv->plug_window),
595               False, NoEventMask, (XEvent *)&xconfigure);
596   gdk_error_trap_pop_ignored ();
597 }
598
599 static void
600 gtk_socket_size_allocate (GtkWidget     *widget,
601                           GtkAllocation *allocation)
602 {
603   GtkSocket *socket = GTK_SOCKET (widget);
604   GtkSocketPrivate *private = socket->priv;
605
606   gtk_widget_set_allocation (widget, allocation);
607   if (gtk_widget_get_realized (widget))
608     {
609       gdk_window_move_resize (gtk_widget_get_window (widget),
610                               allocation->x, allocation->y,
611                               allocation->width, allocation->height);
612
613       if (private->plug_widget)
614         {
615           GtkAllocation child_allocation;
616
617           child_allocation.x = 0;
618           child_allocation.y = 0;
619           child_allocation.width = allocation->width;
620           child_allocation.height = allocation->height;
621
622           gtk_widget_size_allocate (private->plug_widget, &child_allocation);
623         }
624       else if (private->plug_window)
625         {
626           gdk_error_trap_push ();
627
628           if (allocation->width != private->current_width ||
629               allocation->height != private->current_height)
630             {
631               gdk_window_move_resize (private->plug_window,
632                                       0, 0,
633                                       allocation->width, allocation->height);
634               if (private->resize_count)
635                 private->resize_count--;
636               
637               GTK_NOTE (PLUGSOCKET,
638                         g_message ("GtkSocket - allocated: %d %d",
639                                    allocation->width, allocation->height));
640               private->current_width = allocation->width;
641               private->current_height = allocation->height;
642             }
643
644           if (private->need_map)
645             {
646               gdk_window_show (private->plug_window);
647               private->need_map = FALSE;
648             }
649
650           while (private->resize_count)
651             {
652               gtk_socket_send_configure_event (socket);
653               private->resize_count--;
654               GTK_NOTE (PLUGSOCKET,
655                         g_message ("GtkSocket - sending synthetic configure: %d %d",
656                                    allocation->width, allocation->height));
657             }
658
659           gdk_error_trap_pop_ignored ();
660         }
661     }
662 }
663
664 static void
665 gtk_socket_send_key_event (GtkSocket *socket,
666                            GdkEvent  *gdk_event,
667                            gboolean   mask_key_presses)
668 {
669   XKeyEvent xkey;
670   GdkScreen *screen = gdk_window_get_screen (socket->priv->plug_window);
671
672   memset (&xkey, 0, sizeof (xkey));
673   xkey.type = (gdk_event->type == GDK_KEY_PRESS) ? KeyPress : KeyRelease;
674   xkey.window = GDK_WINDOW_XID (socket->priv->plug_window);
675   xkey.root = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
676   xkey.subwindow = None;
677   xkey.time = gdk_event->key.time;
678   xkey.x = 0;
679   xkey.y = 0;
680   xkey.x_root = 0;
681   xkey.y_root = 0;
682   xkey.state = gdk_event->key.state;
683   xkey.keycode = gdk_event->key.hardware_keycode;
684   xkey.same_screen = True;/* FIXME ? */
685
686   gdk_error_trap_push ();
687   XSendEvent (GDK_WINDOW_XDISPLAY (socket->priv->plug_window),
688               GDK_WINDOW_XID (socket->priv->plug_window),
689               False,
690               (mask_key_presses ? KeyPressMask : NoEventMask),
691               (XEvent *)&xkey);
692   gdk_error_trap_pop_ignored ();
693 }
694
695 static gboolean
696 activate_key (GtkAccelGroup  *accel_group,
697               GObject        *acceleratable,
698               guint           accel_key,
699               GdkModifierType accel_mods,
700               GrabbedKey     *grabbed_key)
701 {
702   GdkEvent *gdk_event = gtk_get_current_event ();
703   
704   GtkSocket *socket = g_object_get_data (G_OBJECT (accel_group), "gtk-socket");
705   gboolean retval = FALSE;
706
707   if (gdk_event && gdk_event->type == GDK_KEY_PRESS && socket->priv->plug_window)
708     {
709       gtk_socket_send_key_event (socket, gdk_event, FALSE);
710       retval = TRUE;
711     }
712
713   if (gdk_event)
714     gdk_event_free (gdk_event);
715
716   return retval;
717 }
718
719 static gboolean
720 find_accel_key (GtkAccelKey *key,
721                 GClosure    *closure,
722                 gpointer     data)
723 {
724   GrabbedKey *grabbed_key = data;
725   
726   return (key->accel_key == grabbed_key->accel_key &&
727           key->accel_mods == grabbed_key->accel_mods);
728 }
729
730 /**
731  * gtk_socket_add_grabbed_key:
732  * @socket: a #GtkSocket
733  * @keyval: a key
734  * @modifiers: modifiers for the key
735  *
736  * Called from the GtkSocket platform-specific backend when the
737  * corresponding plug has told the socket to grab a key.
738  */
739 static void
740 gtk_socket_add_grabbed_key (GtkSocket       *socket,
741                             guint            keyval,
742                             GdkModifierType  modifiers)
743 {
744   GClosure *closure;
745   GrabbedKey *grabbed_key;
746
747   grabbed_key = g_new (GrabbedKey, 1);
748   
749   grabbed_key->accel_key = keyval;
750   grabbed_key->accel_mods = modifiers;
751
752   if (gtk_accel_group_find (socket->priv->accel_group,
753                             find_accel_key,
754                             &grabbed_key))
755     {
756       g_warning ("GtkSocket: request to add already present grabbed key %u,%#x\n",
757                  keyval, modifiers);
758       g_free (grabbed_key);
759       return;
760     }
761
762   closure = g_cclosure_new (G_CALLBACK (activate_key), grabbed_key, (GClosureNotify)g_free);
763
764   gtk_accel_group_connect (socket->priv->accel_group, keyval, modifiers, GTK_ACCEL_LOCKED,
765                            closure);
766 }
767
768 /**
769  * gtk_socket_remove_grabbed_key:
770  * @socket: a #GtkSocket
771  * @keyval: a key
772  * @modifiers: modifiers for the key
773  *
774  * Called from the GtkSocket backend when the corresponding plug has
775  * told the socket to remove a key grab.
776  */
777 static void
778 gtk_socket_remove_grabbed_key (GtkSocket      *socket,
779                                guint           keyval,
780                                GdkModifierType modifiers)
781 {
782   if (!gtk_accel_group_disconnect_key (socket->priv->accel_group, keyval, modifiers))
783     g_warning ("GtkSocket: request to remove non-present grabbed key %u,%#x\n",
784                keyval, modifiers);
785 }
786
787 static void
788 socket_update_focus_in (GtkSocket *socket)
789 {
790   GtkSocketPrivate *private = socket->priv;
791   gboolean focus_in = FALSE;
792
793   if (private->plug_window)
794     {
795       GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
796
797       if (gtk_widget_is_toplevel (toplevel) &&
798           gtk_window_has_toplevel_focus (GTK_WINDOW (toplevel)) &&
799           gtk_widget_is_focus (GTK_WIDGET (socket)))
800         focus_in = TRUE;
801     }
802
803   if (focus_in != private->focus_in)
804     {
805       private->focus_in = focus_in;
806
807       if (focus_in)
808         _gtk_xembed_send_focus_message (private->plug_window,
809                                         XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
810       else
811         _gtk_xembed_send_message (private->plug_window,
812                                   XEMBED_FOCUS_OUT, 0, 0, 0);
813     }
814 }
815
816 static void
817 socket_update_active (GtkSocket *socket)
818 {
819   GtkSocketPrivate *private = socket->priv;
820   gboolean active = FALSE;
821
822   if (private->plug_window)
823     {
824       GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
825
826       if (gtk_widget_is_toplevel (toplevel) &&
827           gtk_window_is_active  (GTK_WINDOW (toplevel)))
828         active = TRUE;
829     }
830
831   if (active != private->active)
832     {
833       private->active = active;
834
835       _gtk_xembed_send_message (private->plug_window,
836                                 active ? XEMBED_WINDOW_ACTIVATE : XEMBED_WINDOW_DEACTIVATE,
837                                 0, 0, 0);
838     }
839 }
840
841 static void
842 gtk_socket_hierarchy_changed (GtkWidget *widget,
843                               GtkWidget *old_toplevel)
844 {
845   GtkSocket *socket = GTK_SOCKET (widget);
846   GtkSocketPrivate *private = socket->priv;
847   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
848
849   if (toplevel && !GTK_IS_WINDOW (toplevel))
850     toplevel = NULL;
851
852   if (toplevel != private->toplevel)
853     {
854       if (private->toplevel)
855         {
856           gtk_window_remove_accel_group (GTK_WINDOW (private->toplevel), private->accel_group);
857           g_signal_handlers_disconnect_by_func (private->toplevel,
858                                                 socket_update_focus_in,
859                                                 socket);
860           g_signal_handlers_disconnect_by_func (private->toplevel,
861                                                 socket_update_active,
862                                                 socket);
863         }
864
865       private->toplevel = toplevel;
866
867       if (toplevel)
868         {
869           gtk_window_add_accel_group (GTK_WINDOW (private->toplevel), private->accel_group);
870           g_signal_connect_swapped (private->toplevel, "notify::has-toplevel-focus",
871                                     G_CALLBACK (socket_update_focus_in), socket);
872           g_signal_connect_swapped (private->toplevel, "notify::is-active",
873                                     G_CALLBACK (socket_update_active), socket);
874         }
875
876       socket_update_focus_in (socket);
877       socket_update_active (socket);
878     }
879 }
880
881 static void
882 gtk_socket_grab_notify (GtkWidget *widget,
883                         gboolean   was_grabbed)
884 {
885   GtkSocket *socket = GTK_SOCKET (widget);
886
887   if (!socket->priv->same_app)
888     _gtk_xembed_send_message (socket->priv->plug_window,
889                               was_grabbed ? XEMBED_MODALITY_OFF : XEMBED_MODALITY_ON,
890                               0, 0, 0);
891 }
892
893 static gboolean
894 gtk_socket_key_event (GtkWidget   *widget,
895                       GdkEventKey *event)
896 {
897   GtkSocket *socket = GTK_SOCKET (widget);
898   GtkSocketPrivate *private = socket->priv;
899   
900   if (gtk_widget_has_focus (widget) && private->plug_window && !private->plug_widget)
901     {
902       gtk_socket_send_key_event (socket, (GdkEvent *) event, FALSE);
903
904       return TRUE;
905     }
906   else
907     return FALSE;
908 }
909
910 static void
911 gtk_socket_notify (GObject    *object,
912                    GParamSpec *pspec)
913 {
914   if (strcmp (pspec->name, "is-focus") == 0)
915     socket_update_focus_in (GTK_SOCKET (object));
916
917   if (G_OBJECT_CLASS (gtk_socket_parent_class)->notify)
918     G_OBJECT_CLASS (gtk_socket_parent_class)->notify (object, pspec);
919 }
920
921 /**
922  * gtk_socket_claim_focus:
923  * @socket: a #GtkSocket
924  * @send_event: huh?
925  *
926  * Claims focus for the socket. XXX send_event?
927  */
928 static void
929 gtk_socket_claim_focus (GtkSocket *socket,
930                         gboolean   send_event)
931 {
932   GtkWidget *widget = GTK_WIDGET (socket);
933   GtkSocketPrivate *private = socket->priv;
934
935   if (!send_event)
936     private->focus_in = TRUE;   /* Otherwise, our notify handler will send FOCUS_IN  */
937       
938   /* Oh, the trickery... */
939   
940   gtk_widget_set_can_focus (widget, TRUE);
941   gtk_widget_grab_focus (widget);
942   gtk_widget_set_can_focus (widget, FALSE);
943 }
944
945 static gboolean
946 gtk_socket_focus (GtkWidget       *widget,
947                   GtkDirectionType direction)
948 {
949   GtkSocket *socket = GTK_SOCKET (widget);
950   GtkSocketPrivate *private = socket->priv;
951
952   if (private->plug_widget)
953     return gtk_widget_child_focus (private->plug_widget, direction);
954
955   if (!gtk_widget_is_focus (widget))
956     {
957       gint detail = -1;
958
959       switch (direction)
960         {
961         case GTK_DIR_UP:
962         case GTK_DIR_LEFT:
963         case GTK_DIR_TAB_BACKWARD:
964           detail = XEMBED_FOCUS_LAST;
965           break;
966         case GTK_DIR_DOWN:
967         case GTK_DIR_RIGHT:
968         case GTK_DIR_TAB_FORWARD:
969           detail = XEMBED_FOCUS_FIRST;
970           break;
971         }
972       
973       _gtk_xembed_send_focus_message (private->plug_window, XEMBED_FOCUS_IN, detail);
974       gtk_socket_claim_focus (socket, FALSE);
975  
976       return TRUE;
977     }
978   else
979     return FALSE;
980 }
981
982 static void
983 gtk_socket_remove (GtkContainer *container,
984                    GtkWidget    *child)
985 {
986   GtkSocket *socket = GTK_SOCKET (container);
987   GtkSocketPrivate *private = socket->priv;
988
989   g_return_if_fail (child == private->plug_widget);
990
991   _gtk_plug_remove_from_socket (GTK_PLUG (private->plug_widget), socket);
992 }
993
994 static void
995 gtk_socket_forall (GtkContainer *container,
996                    gboolean      include_internals,
997                    GtkCallback   callback,
998                    gpointer      callback_data)
999 {
1000   GtkSocket *socket = GTK_SOCKET (container);
1001   GtkSocketPrivate *private = socket->priv;
1002
1003   if (private->plug_widget)
1004     (* callback) (private->plug_widget, callback_data);
1005 }
1006
1007 /**
1008  * gtk_socket_add_window:
1009  * @socket: a #GtkSocket
1010  * @xid: the native identifier for a window
1011  * @need_reparent: whether the socket's plug's window needs to be
1012  *                 reparented to the socket
1013  *
1014  * Adds a window to a GtkSocket.
1015  */
1016 static void
1017 gtk_socket_add_window (GtkSocket       *socket,
1018                        Window           xid,
1019                        gboolean         need_reparent)
1020 {
1021   GtkWidget *widget = GTK_WIDGET (socket);
1022   GdkDisplay *display = gtk_widget_get_display (widget);
1023   gpointer user_data = NULL;
1024   GtkSocketPrivate *private = socket->priv;
1025   unsigned long version;
1026   unsigned long flags;
1027
1028   if (GDK_IS_X11_DISPLAY (display))
1029     private->plug_window = gdk_x11_window_lookup_for_display (display, xid);
1030   else
1031     private->plug_window = NULL;
1032
1033   if (private->plug_window)
1034     {
1035       g_object_ref (private->plug_window);
1036       gdk_window_get_user_data (private->plug_window, &user_data);
1037     }
1038
1039   if (user_data) /* A widget's window in this process */
1040     {
1041       GtkWidget *child_widget = user_data;
1042
1043       if (!GTK_IS_PLUG (child_widget))
1044         {
1045           g_warning (G_STRLOC ": Can't add non-GtkPlug to GtkSocket");
1046           private->plug_window = NULL;
1047           gdk_error_trap_pop_ignored ();
1048
1049           return;
1050         }
1051
1052       _gtk_plug_add_to_socket (GTK_PLUG (child_widget), socket);
1053     }
1054   else  /* A foreign window */
1055     {
1056       GdkDragProtocol protocol;
1057
1058       gdk_error_trap_push ();
1059
1060       if (!private->plug_window)
1061         {
1062           if (GDK_IS_X11_DISPLAY (display))
1063             private->plug_window = gdk_x11_window_foreign_new_for_display (display, xid);
1064           if (!private->plug_window) /* was deleted before we could get it */
1065             {
1066               gdk_error_trap_pop_ignored ();
1067               return;
1068             }
1069         }
1070
1071       XSelectInput (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (socket))),
1072                     GDK_WINDOW_XID (private->plug_window),
1073                     StructureNotifyMask | PropertyChangeMask);
1074
1075       if (gdk_error_trap_pop ())
1076         {
1077           g_object_unref (private->plug_window);
1078           private->plug_window = NULL;
1079           return;
1080         }
1081       
1082       /* OK, we now will reliably get destroy notification on socket->plug_window */
1083
1084       gdk_error_trap_push ();
1085
1086       if (need_reparent)
1087         {
1088           gdk_window_hide (private->plug_window); /* Shouldn't actually be necessary for XEMBED, but just in case */
1089           gdk_window_reparent (private->plug_window,
1090                                gtk_widget_get_window (widget),
1091                                0, 0);
1092         }
1093
1094       private->have_size = FALSE;
1095
1096       private->xembed_version = -1;
1097       if (xembed_get_info (private->plug_window, &version, &flags))
1098         {
1099           private->xembed_version = MIN (GTK_XEMBED_PROTOCOL_VERSION, version);
1100           private->is_mapped = (flags & XEMBED_MAPPED) != 0;
1101         }
1102       else
1103         {
1104           /* FIXME, we should probably actually check the state before we started */
1105           private->is_mapped = TRUE;
1106         }
1107
1108       private->need_map = private->is_mapped;
1109
1110       protocol = gdk_window_get_drag_protocol (private->plug_window, NULL);
1111       if (protocol)
1112         gtk_drag_dest_set_proxy (GTK_WIDGET (socket), private->plug_window,
1113                                  protocol, TRUE);
1114
1115       gdk_error_trap_pop_ignored ();
1116
1117       gdk_window_add_filter (private->plug_window,
1118                              gtk_socket_filter_func,
1119                              socket);
1120
1121 #ifdef HAVE_XFIXES
1122       gdk_error_trap_push ();
1123       XFixesChangeSaveSet (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (socket))),
1124                            GDK_WINDOW_XID (private->plug_window),
1125                            SetModeInsert, SaveSetRoot, SaveSetUnmap);
1126       gdk_error_trap_pop_ignored ();
1127 #endif
1128       _gtk_xembed_send_message (private->plug_window,
1129                                 XEMBED_EMBEDDED_NOTIFY, 0,
1130                                 GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (socket))),
1131                                 private->xembed_version);
1132
1133       socket_update_active (socket);
1134       socket_update_focus_in (socket);
1135
1136       gtk_widget_queue_resize (GTK_WIDGET (socket));
1137     }
1138
1139   if (private->plug_window)
1140     g_signal_emit (socket, socket_signals[PLUG_ADDED], 0);
1141 }
1142
1143 /**
1144  * gtk_socket_handle_map_request:
1145  * @socket: a #GtkSocket
1146  *
1147  * Called from the GtkSocket backend when the plug has been mapped.
1148  */
1149 static void
1150 gtk_socket_handle_map_request (GtkSocket *socket)
1151 {
1152   GtkSocketPrivate *private = socket->priv;
1153   if (!private->is_mapped)
1154     {
1155       private->is_mapped = TRUE;
1156       private->need_map = TRUE;
1157
1158       gtk_widget_queue_resize (GTK_WIDGET (socket));
1159     }
1160 }
1161
1162 /**
1163  * gtk_socket_unmap_notify:
1164  * @socket: a #GtkSocket
1165  *
1166  * Called from the GtkSocket backend when the plug has been unmapped ???
1167  */
1168 static void
1169 gtk_socket_unmap_notify (GtkSocket *socket)
1170 {
1171   GtkSocketPrivate *private = socket->priv;
1172   if (private->is_mapped)
1173     {
1174       private->is_mapped = FALSE;
1175       gtk_widget_queue_resize (GTK_WIDGET (socket));
1176     }
1177 }
1178
1179 /**
1180  * gtk_socket_advance_toplevel_focus:
1181  * @socket: a #GtkSocket
1182  * @direction: a direction
1183  *
1184  * Called from the GtkSocket backend when the corresponding plug
1185  * has told the socket to move the focus.
1186  */
1187 static void
1188 gtk_socket_advance_toplevel_focus (GtkSocket        *socket,
1189                                    GtkDirectionType  direction)
1190 {
1191   GtkBin *bin;
1192   GtkWindow *window;
1193   GtkContainer *container;
1194   GtkWidget *child;
1195   GtkWidget *focus_widget;
1196   GtkWidget *toplevel;
1197   GtkWidget *old_focus_child;
1198   GtkWidget *parent;
1199
1200   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
1201   if (!toplevel)
1202     return;
1203
1204   if (!gtk_widget_is_toplevel (toplevel) || GTK_IS_PLUG (toplevel))
1205     {
1206       gtk_widget_child_focus (toplevel,direction);
1207       return;
1208     }
1209
1210   container = GTK_CONTAINER (toplevel);
1211   window = GTK_WINDOW (toplevel);
1212   bin = GTK_BIN (toplevel);
1213
1214   /* This is a copy of gtk_window_focus(), modified so that we
1215    * can detect wrap-around.
1216    */
1217   old_focus_child = gtk_container_get_focus_child (container);
1218   
1219   if (old_focus_child)
1220     {
1221       if (gtk_widget_child_focus (old_focus_child, direction))
1222         return;
1223
1224       /* We are allowed exactly one wrap-around per sequence of focus
1225        * events
1226        */
1227       if (_gtk_xembed_get_focus_wrapped ())
1228         return;
1229       else
1230         _gtk_xembed_set_focus_wrapped ();
1231     }
1232
1233   focus_widget = gtk_window_get_focus (window);
1234   if (window)
1235     {
1236       /* Wrapped off the end, clear the focus setting for the toplevel */
1237       parent = gtk_widget_get_parent (focus_widget);
1238       while (parent)
1239         {
1240           gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
1241           parent = gtk_widget_get_parent (parent);
1242         }
1243       
1244       gtk_window_set_focus (GTK_WINDOW (container), NULL);
1245     }
1246
1247   /* Now try to focus the first widget in the window */
1248   child = gtk_bin_get_child (bin);
1249   if (child)
1250     {
1251       if (gtk_widget_child_focus (child, direction))
1252         return;
1253     }
1254 }
1255
1256 static gboolean
1257 xembed_get_info (GdkWindow     *window,
1258                  unsigned long *version,
1259                  unsigned long *flags)
1260 {
1261   GdkDisplay *display = gdk_window_get_display (window);
1262   Atom xembed_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO");
1263   Atom type;
1264   int format;
1265   unsigned long nitems, bytes_after;
1266   unsigned char *data;
1267   unsigned long *data_long;
1268   int status;
1269   
1270   gdk_error_trap_push ();
1271   status = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
1272                                GDK_WINDOW_XID (window),
1273                                xembed_info_atom,
1274                                0, 2, False,
1275                                xembed_info_atom, &type, &format,
1276                                &nitems, &bytes_after, &data);
1277   gdk_error_trap_pop_ignored ();
1278
1279   if (status != Success)
1280     return FALSE;               /* Window vanished? */
1281
1282   if (type == None)             /* No info property */
1283     return FALSE;
1284
1285   if (type != xembed_info_atom)
1286     {
1287       g_warning ("_XEMBED_INFO property has wrong type\n");
1288       return FALSE;
1289     }
1290   
1291   if (nitems < 2)
1292     {
1293       g_warning ("_XEMBED_INFO too short\n");
1294       XFree (data);
1295       return FALSE;
1296     }
1297   
1298   data_long = (unsigned long *)data;
1299   if (version)
1300     *version = data_long[0];
1301   if (flags)
1302     *flags = data_long[1] & XEMBED_MAPPED;
1303   
1304   XFree (data);
1305   return TRUE;
1306 }
1307
1308 static void
1309 handle_xembed_message (GtkSocket        *socket,
1310                        XEmbedMessageType message,
1311                        glong             detail,
1312                        glong             data1,
1313                        glong             data2,
1314                        guint32           time)
1315 {
1316   GTK_NOTE (PLUGSOCKET,
1317             g_message ("GtkSocket: %s received", _gtk_xembed_message_name (message)));
1318   
1319   switch (message)
1320     {
1321     case XEMBED_EMBEDDED_NOTIFY:
1322     case XEMBED_WINDOW_ACTIVATE:
1323     case XEMBED_WINDOW_DEACTIVATE:
1324     case XEMBED_MODALITY_ON:
1325     case XEMBED_MODALITY_OFF:
1326     case XEMBED_FOCUS_IN:
1327     case XEMBED_FOCUS_OUT:
1328       g_warning ("GtkSocket: Invalid _XEMBED message %s received", _gtk_xembed_message_name (message));
1329       break;
1330       
1331     case XEMBED_REQUEST_FOCUS:
1332       gtk_socket_claim_focus (socket, TRUE);
1333       break;
1334
1335     case XEMBED_FOCUS_NEXT:
1336     case XEMBED_FOCUS_PREV:
1337       gtk_socket_advance_toplevel_focus (socket,
1338                                          (message == XEMBED_FOCUS_NEXT ?
1339                                           GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD));
1340       break;
1341       
1342     case XEMBED_GTK_GRAB_KEY:
1343       gtk_socket_add_grabbed_key (socket, data1, data2);
1344       break; 
1345     case XEMBED_GTK_UNGRAB_KEY:
1346       gtk_socket_remove_grabbed_key (socket, data1, data2);
1347       break;
1348
1349     case XEMBED_GRAB_KEY:
1350     case XEMBED_UNGRAB_KEY:
1351       break;
1352       
1353     default:
1354       GTK_NOTE (PLUGSOCKET,
1355                 g_message ("GtkSocket: Ignoring unknown _XEMBED message of type %d", message));
1356       break;
1357     }
1358 }
1359
1360 static GdkFilterReturn
1361 gtk_socket_filter_func (GdkXEvent *gdk_xevent,
1362                         GdkEvent  *event,
1363                         gpointer   data)
1364 {
1365   GtkSocket *socket;
1366   GtkWidget *widget;
1367   GdkDisplay *display;
1368   XEvent *xevent;
1369   GtkSocketPrivate *private;
1370
1371   GdkFilterReturn return_val;
1372
1373   socket = GTK_SOCKET (data);
1374   private = socket->priv;
1375
1376   return_val = GDK_FILTER_CONTINUE;
1377
1378   if (private->plug_widget)
1379     return return_val;
1380
1381   widget = GTK_WIDGET (socket);
1382   xevent = (XEvent *)gdk_xevent;
1383   display = gtk_widget_get_display (widget);
1384
1385   switch (xevent->type)
1386     {
1387     case ClientMessage:
1388       if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED"))
1389         {
1390           _gtk_xembed_push_message (xevent);
1391           handle_xembed_message (socket,
1392                                  xevent->xclient.data.l[1],
1393                                  xevent->xclient.data.l[2],
1394                                  xevent->xclient.data.l[3],
1395                                  xevent->xclient.data.l[4],
1396                                  xevent->xclient.data.l[0]);
1397           _gtk_xembed_pop_message ();
1398           
1399           return_val = GDK_FILTER_REMOVE;
1400         }
1401       break;
1402
1403     case CreateNotify:
1404       {
1405         XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
1406
1407         if (!private->plug_window)
1408           {
1409             gtk_socket_add_window (socket, xcwe->window, FALSE);
1410
1411             if (private->plug_window)
1412               {
1413                 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window created"));
1414               }
1415           }
1416         
1417         return_val = GDK_FILTER_REMOVE;
1418         
1419         break;
1420       }
1421
1422     case ConfigureRequest:
1423       {
1424         XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
1425         
1426         if (!private->plug_window)
1427           gtk_socket_add_window (socket, xcre->window, FALSE);
1428         
1429         if (private->plug_window)
1430           {
1431             if (xcre->value_mask & (CWWidth | CWHeight))
1432               {
1433                 GTK_NOTE (PLUGSOCKET,
1434                           g_message ("GtkSocket - configure request: %d %d",
1435                                      private->request_width,
1436                                      private->request_height));
1437
1438                 private->resize_count++;
1439                 gtk_widget_queue_resize (widget);
1440               }
1441             else if (xcre->value_mask & (CWX | CWY))
1442               {
1443                 gtk_socket_send_configure_event (socket);
1444               }
1445             /* Ignore stacking requests. */
1446             
1447             return_val = GDK_FILTER_REMOVE;
1448           }
1449         break;
1450       }
1451
1452     case DestroyNotify:
1453       {
1454         XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
1455
1456         /* Note that we get destroy notifies both from SubstructureNotify on
1457          * our window and StructureNotify on socket->plug_window
1458          */
1459         if (private->plug_window && (xdwe->window == GDK_WINDOW_XID (private->plug_window)))
1460           {
1461             gboolean result;
1462             
1463             GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - destroy notify"));
1464             
1465             gdk_window_destroy_notify (private->plug_window);
1466             gtk_socket_end_embedding (socket);
1467
1468             g_object_ref (widget);
1469             g_signal_emit_by_name (widget, "plug-removed", &result);
1470             if (!result)
1471               gtk_widget_destroy (widget);
1472             g_object_unref (widget);
1473             
1474             return_val = GDK_FILTER_REMOVE;
1475           }
1476         break;
1477       }
1478
1479     case FocusIn:
1480       if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
1481         {
1482           gtk_socket_claim_focus (socket, TRUE);
1483         }
1484       return_val = GDK_FILTER_REMOVE;
1485       break;
1486     case FocusOut:
1487       return_val = GDK_FILTER_REMOVE;
1488       break;
1489     case MapRequest:
1490       if (!private->plug_window)
1491         {
1492           gtk_socket_add_window (socket, xevent->xmaprequest.window, FALSE);
1493         }
1494         
1495       if (private->plug_window)
1496         {
1497           GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Map Request"));
1498
1499           gtk_socket_handle_map_request (socket);
1500           return_val = GDK_FILTER_REMOVE;
1501         }
1502       break;
1503     case PropertyNotify:
1504       if (private->plug_window &&
1505           xevent->xproperty.window == GDK_WINDOW_XID (private->plug_window))
1506         {
1507           GdkDragProtocol protocol;
1508
1509           if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_NORMAL_HINTS"))
1510             {
1511               GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - received PropertyNotify for plug's WM_NORMAL_HINTS"));
1512               private->have_size = FALSE;
1513               gtk_widget_queue_resize (widget);
1514               return_val = GDK_FILTER_REMOVE;
1515             }
1516           else if ((xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndAware")) ||
1517               (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO")))
1518             {
1519               gdk_error_trap_push ();
1520               protocol = gdk_window_get_drag_protocol (private->plug_window, NULL);
1521               if (protocol)
1522                 gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
1523                                          private->plug_window,
1524                                          protocol, TRUE);
1525
1526               gdk_error_trap_pop_ignored ();
1527               return_val = GDK_FILTER_REMOVE;
1528             }
1529           else if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO"))
1530             {
1531               unsigned long flags;
1532               
1533               if (xembed_get_info (private->plug_window, NULL, &flags))
1534                 {
1535                   gboolean was_mapped = private->is_mapped;
1536                   gboolean is_mapped = (flags & XEMBED_MAPPED) != 0;
1537
1538                   if (was_mapped != is_mapped)
1539                     {
1540                       if (is_mapped)
1541                         gtk_socket_handle_map_request (socket);
1542                       else
1543                         {
1544                           gdk_error_trap_push ();
1545                           gdk_window_show (private->plug_window);
1546                           gdk_error_trap_pop_ignored ();
1547                           
1548                           gtk_socket_unmap_notify (socket);
1549                         }
1550                     }
1551                 }
1552               return_val = GDK_FILTER_REMOVE;
1553             }
1554         }
1555       break;
1556     case ReparentNotify:
1557       {
1558         GdkWindow *window;
1559         XReparentEvent *xre = &xevent->xreparent;
1560
1561         window = gtk_widget_get_window (widget);
1562
1563         GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - ReparentNotify received"));
1564         if (!private->plug_window &&
1565             xre->parent == GDK_WINDOW_XID (window))
1566           {
1567             gtk_socket_add_window (socket, xre->window, FALSE);
1568             
1569             if (private->plug_window)
1570               {
1571                 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window reparented"));
1572               }
1573             
1574             return_val = GDK_FILTER_REMOVE;
1575           }
1576         else
1577           {
1578             if (private->plug_window &&
1579                 xre->window == GDK_WINDOW_XID (private->plug_window) &&
1580                 xre->parent != GDK_WINDOW_XID (window))
1581               {
1582                 gboolean result;
1583
1584                 gtk_socket_end_embedding (socket);
1585
1586                 g_object_ref (widget);
1587                 g_signal_emit_by_name (widget, "plug-removed", &result);
1588                 if (!result)
1589                   gtk_widget_destroy (widget);
1590                 g_object_unref (widget);
1591
1592                 return_val = GDK_FILTER_REMOVE;
1593               }
1594           }
1595
1596         break;
1597       }
1598     case UnmapNotify:
1599       if (private->plug_window &&
1600           xevent->xunmap.window == GDK_WINDOW_XID (private->plug_window))
1601         {
1602           GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Unmap notify"));
1603
1604           gtk_socket_unmap_notify (socket);
1605           return_val = GDK_FILTER_REMOVE;
1606         }
1607       break;
1608       
1609     }
1610   
1611   return return_val;
1612 }