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