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