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