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