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