]> Pileus Git - ~andy/gtk/blob - gtk/gtksocket.c
geez, don't call g_list funcs on GSList
[~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 "gdk/gdkkeysyms.h"
29 #include "gtkmain.h"
30 #include "gtkwindow.h"
31 #include "gtksignal.h"
32 #include "gtksocket.h"
33 #include "gtkdnd.h"
34
35 #include "x11/gdkx.h"
36
37 #include "xembed.h"
38
39 /* Forward declararations */
40
41 static void            gtk_socket_class_init           (GtkSocketClass   *klass);
42 static void            gtk_socket_init                 (GtkSocket        *socket);
43 static void            gtk_socket_realize              (GtkWidget        *widget);
44 static void            gtk_socket_unrealize            (GtkWidget        *widget);
45 static void            gtk_socket_size_request         (GtkWidget        *widget,
46                                                         GtkRequisition   *requisition);
47 static void            gtk_socket_size_allocate        (GtkWidget        *widget,
48                                                         GtkAllocation    *allocation);
49 static void            gtk_socket_hierarchy_changed    (GtkWidget        *widget);
50 static void            gtk_socket_grab_notify          (GtkWidget        *widget,
51                                                         gboolean          was_grabbed);
52 static gboolean        gtk_socket_key_press_event      (GtkWidget        *widget,
53                                                         GdkEventKey      *event);
54 static gboolean        gtk_socket_focus_in_event       (GtkWidget        *widget,
55                                                         GdkEventFocus    *event);
56 static void            gtk_socket_claim_focus          (GtkSocket        *socket);
57 static gboolean        gtk_socket_focus_out_event      (GtkWidget        *widget,
58                                                         GdkEventFocus    *event);
59 static void            gtk_socket_send_configure_event (GtkSocket        *socket);
60 static gboolean        gtk_socket_focus                (GtkWidget        *widget,
61                                                         GtkDirectionType  direction);
62 static GdkFilterReturn gtk_socket_filter_func          (GdkXEvent        *gdk_xevent,
63                                                         GdkEvent         *event,
64                                                         gpointer          data);
65
66 static void send_xembed_message (GtkSocket *socket,
67                                  glong      message,
68                                  glong      detail,
69                                  glong      data1,
70                                  glong      data2,
71                                  guint32    time);
72
73 /* From Tk */
74 #define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
75
76 /* Local data */
77
78 static GtkWidgetClass *parent_class = NULL;
79
80 GtkType
81 gtk_socket_get_type (void)
82 {
83   static GtkType socket_type = 0;
84
85   if (!socket_type)
86     {
87       static const GTypeInfo socket_info =
88       {
89         sizeof (GtkSocketClass),
90         NULL,           /* base_init */
91         NULL,           /* base_finalize */
92         (GClassInitFunc) gtk_socket_class_init,
93         NULL,           /* class_finalize */
94         NULL,           /* class_data */
95         sizeof (GtkSocket),
96         16,             /* n_preallocs */
97         (GInstanceInitFunc) gtk_socket_init,
98       };
99
100       socket_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkSocket", &socket_info, 0);
101     }
102
103   return socket_type;
104 }
105
106 static void
107 gtk_socket_class_init (GtkSocketClass *class)
108 {
109   GtkWidgetClass *widget_class;
110   GtkContainerClass *container_class;
111
112   widget_class = (GtkWidgetClass*) class;
113   container_class = (GtkContainerClass*) class;
114
115   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
116
117   widget_class->realize = gtk_socket_realize;
118   widget_class->unrealize = gtk_socket_unrealize;
119   widget_class->size_request = gtk_socket_size_request;
120   widget_class->size_allocate = gtk_socket_size_allocate;
121   widget_class->hierarchy_changed = gtk_socket_hierarchy_changed;
122 #if 0  
123   widget_class->grab_notify = gtk_socket_grab_notify;
124 #endif  
125   widget_class->key_press_event = gtk_socket_key_press_event;
126   widget_class->focus_in_event = gtk_socket_focus_in_event;
127   widget_class->focus_out_event = gtk_socket_focus_out_event;
128
129   widget_class->focus = gtk_socket_focus;
130 }
131
132 static void
133 gtk_socket_init (GtkSocket *socket)
134 {
135   socket->request_width = 0;
136   socket->request_height = 0;
137   socket->current_width = 0;
138   socket->current_height = 0;
139   
140   socket->plug_window = NULL;
141   socket->same_app = FALSE;
142   socket->focus_in = FALSE;
143   socket->have_size = FALSE;
144   socket->need_map = FALSE;
145 }
146
147 GtkWidget*
148 gtk_socket_new (void)
149 {
150   GtkSocket *socket;
151
152   socket = g_object_new (GTK_TYPE_SOCKET, NULL);
153
154   return GTK_WIDGET (socket);
155 }
156
157 void           
158 gtk_socket_steal (GtkSocket *socket, GdkNativeWindow id)
159 {
160   GtkWidget *widget;
161   gpointer user_data = NULL;
162   
163   widget = GTK_WIDGET (socket);
164   
165   socket->plug_window = gdk_window_lookup (id);
166
167   gdk_error_trap_push ();
168
169   if (socket->plug_window)
170     gdk_window_get_user_data (socket->plug_window,
171                               &user_data);
172   
173   if (user_data)      
174     {
175       /*
176         GtkWidget *child_widget;
177
178         child_widget = GTK_WIDGET (socket->plug_window->user_data);
179       */
180
181       g_warning("Stealing from same app not yet implemented");
182       
183       socket->same_app = TRUE;
184     }
185   else
186     {
187       socket->plug_window = gdk_window_foreign_new (id);
188       if (!socket->plug_window) /* was deleted before we could get it */
189         {
190           gdk_error_trap_pop ();
191           return;
192         }
193         
194       socket->same_app = FALSE;
195       socket->have_size = FALSE;
196
197       XSelectInput (GDK_DISPLAY (),
198                     GDK_WINDOW_XWINDOW(socket->plug_window),
199                     StructureNotifyMask | PropertyChangeMask);
200
201       gtk_widget_queue_resize (widget);
202     }
203
204   gdk_window_hide (socket->plug_window);
205   gdk_window_reparent (socket->plug_window, widget->window, 0, 0);
206
207   gdk_flush ();
208   gdk_error_trap_pop ();
209   
210   socket->need_map = TRUE;
211 }
212
213 static void
214 gtk_socket_realize (GtkWidget *widget)
215 {
216   GtkSocket *socket;
217   GdkWindowAttr attributes;
218   gint attributes_mask;
219   XWindowAttributes xattrs;
220
221   g_return_if_fail (widget != NULL);
222   g_return_if_fail (GTK_IS_SOCKET (widget));
223
224   socket = GTK_SOCKET (widget);
225   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
226
227   attributes.window_type = GDK_WINDOW_CHILD;
228   attributes.x = widget->allocation.x;
229   attributes.y = widget->allocation.y;
230   attributes.width = widget->allocation.width;
231   attributes.height = widget->allocation.height;
232   attributes.wclass = GDK_INPUT_OUTPUT;
233   attributes.visual = gtk_widget_get_visual (widget);
234   attributes.colormap = gtk_widget_get_colormap (widget);
235   attributes.event_mask = GDK_FOCUS_CHANGE_MASK;
236
237   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
238
239   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), 
240                                    &attributes, attributes_mask);
241   gdk_window_set_user_data (widget->window, socket);
242
243   widget->style = gtk_style_attach (widget->style, widget->window);
244   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
245
246   XGetWindowAttributes (GDK_DISPLAY (),
247                         GDK_WINDOW_XWINDOW (widget->window),
248                         &xattrs);
249
250   XSelectInput (GDK_DISPLAY (),
251                 GDK_WINDOW_XWINDOW(widget->window), 
252                 xattrs.your_event_mask | 
253                 SubstructureNotifyMask | SubstructureRedirectMask);
254
255   gdk_window_add_filter (widget->window, gtk_socket_filter_func, widget);
256
257   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
258
259   /* We sync here so that we make sure that if the XID for
260    * our window is passed to another application, SubstructureRedirectMask
261    * will be set by the time the other app creates its window.
262    */
263   gdk_flush();
264 }
265
266 static void
267 gtk_socket_unrealize (GtkWidget *widget)
268 {
269   GtkSocket *socket;
270
271   g_return_if_fail (widget != NULL);
272   g_return_if_fail (GTK_IS_SOCKET (widget));
273
274   socket = GTK_SOCKET (widget);
275
276   if (socket->plug_window)
277     {
278       GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
279       if (toplevel && GTK_IS_WINDOW (toplevel))
280         gtk_window_remove_embedded_xid (GTK_WINDOW (toplevel), 
281                                         GDK_WINDOW_XWINDOW (socket->plug_window));
282
283       socket->plug_window = NULL;
284     }
285
286 #if 0  
287   if (socket->grabbed_keys)
288     {
289       g_hash_table_foreach (socket->grabbed_keys, (GHFunc)g_free, NULL);
290       g_hash_table_destroy (socket->grabbed_keys);
291       socket->grabbed_keys = NULL;
292     }
293 #endif
294   
295   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
296     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
297 }
298   
299 static void 
300 gtk_socket_size_request (GtkWidget      *widget,
301                          GtkRequisition *requisition)
302 {
303   GtkSocket *socket;
304
305   g_return_if_fail (widget != NULL);
306   g_return_if_fail (GTK_IS_SOCKET (widget));
307   g_return_if_fail (requisition != NULL);
308   
309   socket = GTK_SOCKET (widget);
310
311   if (!socket->have_size && socket->plug_window)
312     {
313       XSizeHints hints;
314       long supplied;
315
316       gdk_error_trap_push ();
317       
318       if (XGetWMNormalHints (GDK_DISPLAY(),
319                              GDK_WINDOW_XWINDOW (socket->plug_window),
320                              &hints, &supplied))
321         {
322           /* This is obsolete, according the X docs, but many programs
323            * still use it */
324           if (hints.flags & (PSize | USSize))
325             {
326               socket->request_width = hints.width;
327               socket->request_height = hints.height;
328             }
329           else if (hints.flags & PMinSize)
330             {
331               socket->request_width = hints.min_width;
332               socket->request_height = hints.min_height;
333             }
334           else if (hints.flags & PBaseSize)
335             {
336               socket->request_width = hints.base_width;
337               socket->request_height = hints.base_height;
338             }
339         }
340       socket->have_size = TRUE; /* don't check again? */
341
342       gdk_error_trap_pop ();
343     }
344
345   requisition->width = MAX (socket->request_width, 1);
346   requisition->height = MAX (socket->request_height, 1);
347 }
348
349 static void
350 gtk_socket_size_allocate (GtkWidget     *widget,
351                           GtkAllocation *allocation)
352 {
353   GtkSocket *socket;
354
355   g_return_if_fail (widget != NULL);
356   g_return_if_fail (GTK_IS_SOCKET (widget));
357   g_return_if_fail (allocation != NULL);
358
359   socket = GTK_SOCKET (widget);
360
361   widget->allocation = *allocation;
362   if (GTK_WIDGET_REALIZED (widget))
363     {
364       gdk_window_move_resize (widget->window,
365                               allocation->x, allocation->y,
366                               allocation->width, allocation->height);
367
368       if (socket->plug_window)
369         {
370           gdk_error_trap_push ();
371           
372           if (!socket->need_map &&
373               (allocation->width == socket->current_width) &&
374               (allocation->height == socket->current_height))
375             {
376               gtk_socket_send_configure_event (socket);
377               GTK_NOTE(PLUGSOCKET, 
378                        g_message ("GtkSocket - allocated no change: %d %d",
379                                   allocation->width, allocation->height));
380             }
381           else
382             {
383               gdk_window_move_resize (socket->plug_window,
384                                       0, 0,
385                                       allocation->width, allocation->height);
386               GTK_NOTE(PLUGSOCKET,
387                        g_message ("GtkSocket - allocated: %d %d",
388                                   allocation->width, allocation->height));
389               socket->current_width = allocation->width;
390               socket->current_height = allocation->height;
391             }
392
393           if (socket->need_map)
394             {
395               gdk_window_show (socket->plug_window);
396               socket->need_map = FALSE;
397             }
398
399           gdk_flush ();
400           gdk_error_trap_pop ();
401         }
402     }
403 }
404
405 #if 0
406
407 typedef struct
408 {
409   guint                  accelerator_key;
410   GdkModifierType        accelerator_mods;
411 } GrabbedKey;
412
413 static guint
414 grabbed_key_hash (gconstpointer a)
415 {
416   const GrabbedKey *key = a;
417   guint h;
418   
419   h = key->accelerator_key << 16;
420   h ^= key->accelerator_key >> 16;
421   h ^= key->accelerator_mods;
422
423   return h;
424 }
425
426 static gboolean
427 grabbed_key_equal (gconstpointer a, gconstpointer b)
428 {
429   const GrabbedKey *keya = a;
430   const GrabbedKey *keyb = b;
431
432   return (keya->accelerator_key == keyb->accelerator_key &&
433           keya->accelerator_mods == keyb->accelerator_mods);
434 }
435
436 static void
437 add_grabbed_key (GtkSocket      *socket,
438                  guint           hardware_keycode,
439                  GdkModifierType mods)
440 {
441   GrabbedKey key;
442   GrabbedKey *new_key;
443   GrabbedKey *found_key;
444
445   if (socket->grabbed_keys)
446     {
447       key.accelerator_key = hardware_keycode;
448       key.accelerator_mods = mods;
449
450       found_key = g_hash_table_lookup (socket->grabbed_keys, &key);
451
452       if (found_key)
453         {
454           g_warning ("GtkSocket: request to add already present grabbed key %u,%#x\n",
455                      hardware_keycode, mods);
456           return;
457         }
458     }
459   
460   if (!socket->grabbed_keys)
461     socket->grabbed_keys = g_hash_table_new (grabbed_key_hash, grabbed_key_equal);
462
463   new_key = g_new (GrabbedKey, 1);
464   
465   new_key->accelerator_key = hardware_keycode;
466   new_key->accelerator_mods = mods;
467
468   g_hash_table_insert (socket->grabbed_keys, new_key, new_key);
469 }
470
471 static void
472 remove_grabbed_key (GtkSocket      *socket,
473                     guint           hardware_keycode,
474                     GdkModifierType mods)
475 {
476   GrabbedKey key;
477   GrabbedKey *found_key = NULL;
478
479   if (socket->grabbed_keys)
480     {
481       key.accelerator_key = hardware_keycode;
482       key.accelerator_mods = mods;
483
484       found_key = g_hash_table_lookup (socket->grabbed_keys, &key);
485     }
486
487   if (found_key)
488     {
489       g_hash_table_remove (socket->grabbed_keys, &key);
490       g_free (found_key);
491     }
492   else
493     g_warning ("GtkSocket: request to remove non-present grabbed key %u,%#x\n",
494                hardware_keycode, mods);
495 }
496
497 static gboolean
498 toplevel_key_press_handler (GtkWidget   *toplevel,
499                             GdkEventKey *event,
500                             GtkSocket   *socket)
501 {
502   GrabbedKey search_key;
503
504   search_key.accelerator_key = event->hardware_keycode;
505   search_key.accelerator_mods = event->state;
506
507   if (socket->grabbed_keys &&
508       g_hash_table_lookup (socket->grabbed_keys, &search_key))
509     {
510       gtk_socket_key_press_event (GTK_WIDGET (socket), event);
511       gtk_signal_emit_stop_by_name (GTK_OBJECT (toplevel), "key_press_event");
512
513       return TRUE;
514     }
515   else
516     return FALSE;
517 }
518
519 #endif
520
521 static void
522 toplevel_focus_in_handler (GtkWidget     *toplevel,
523                            GdkEventFocus *event,
524                            GtkSocket     *socket)
525 {
526   /* It appears spurious focus in events can occur when
527    *  the window is hidden. So we'll just check to see if
528    *  the window is visible before actually handling the
529    *  event. (Comment from gtkwindow.c)
530    */
531   if (GTK_WIDGET_VISIBLE (toplevel))
532     send_xembed_message (socket, XEMBED_WINDOW_ACTIVATE, 0, 0, 0,
533                          gtk_get_current_event_time ()); /* Will be GDK_CURRENT_TIME */
534 }
535
536 static void
537 toplevel_focus_out_handler (GtkWidget     *toplevel,
538                             GdkEventFocus *event,
539                             GtkSocket     *socket)
540 {
541   send_xembed_message (socket, XEMBED_WINDOW_DEACTIVATE, 0, 0, 0,
542                        gtk_get_current_event_time ()); /* Will be GDK_CURRENT_TIME */
543 }
544
545 static void
546 gtk_socket_hierarchy_changed (GtkWidget *widget)
547 {
548   GtkSocket *socket = GTK_SOCKET (widget);
549   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
550
551   if (toplevel && !GTK_IS_WINDOW (toplevel))
552     toplevel = NULL;
553
554   if (toplevel != socket->toplevel)
555     {
556       if (socket->toplevel)
557         {
558 #if 0
559           gtk_signal_disconnect_by_func (GTK_OBJECT (socket->toplevel), GTK_SIGNAL_FUNC (toplevel_key_press_handler), socket);
560 #endif    
561           gtk_signal_disconnect_by_func (GTK_OBJECT (socket->toplevel), GTK_SIGNAL_FUNC (toplevel_focus_in_handler), socket);
562           gtk_signal_disconnect_by_func (GTK_OBJECT (socket->toplevel), GTK_SIGNAL_FUNC (toplevel_focus_out_handler), socket);
563         }
564
565       socket->toplevel = toplevel;
566
567       if (toplevel)
568         {
569 #if 0
570           gtk_signal_connect (GTK_OBJECT (socket->toplevel), "key_press_event",
571                               GTK_SIGNAL_FUNC (toplevel_key_press_handler), socket);
572 #endif
573           gtk_signal_connect (GTK_OBJECT (socket->toplevel), "focus_in_event",
574                               GTK_SIGNAL_FUNC (toplevel_focus_in_handler), socket);
575           gtk_signal_connect (GTK_OBJECT (socket->toplevel), "focus_out_event",
576                               GTK_SIGNAL_FUNC (toplevel_focus_out_handler), socket);
577         }
578     }
579 }
580
581 static void
582 gtk_socket_grab_notify (GtkWidget *widget,
583                         gboolean   was_grabbed)
584 {
585   send_xembed_message (GTK_SOCKET (widget),
586                        was_grabbed ? XEMBED_MODALITY_OFF : XEMBED_MODALITY_ON,
587                        0, 0, 0, gtk_get_current_event_time ());
588 }
589
590 static gboolean
591 gtk_socket_key_press_event (GtkWidget   *widget,
592                             GdkEventKey *event)
593 {
594   GtkSocket *socket = GTK_SOCKET (widget);
595   
596   if (socket->plug_window)
597     {
598       XEvent xevent;
599       
600       xevent.xkey.type = KeyPress;
601       xevent.xkey.display = GDK_WINDOW_XDISPLAY (event->window);
602       xevent.xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
603       xevent.xkey.root = GDK_ROOT_WINDOW ();
604       xevent.xkey.time = event->time;
605       /* FIXME, the following might cause problems for non-GTK apps */
606       xevent.xkey.x = 0;
607       xevent.xkey.y = 0;
608       xevent.xkey.x_root = 0;
609       xevent.xkey.y_root = 0;
610       xevent.xkey.state = event->state;
611       xevent.xkey.keycode = event->hardware_keycode;
612       xevent.xkey.same_screen = TRUE; /* FIXME ? */
613       
614       gdk_error_trap_push ();
615       XSendEvent (gdk_display,
616                   GDK_WINDOW_XWINDOW (socket->plug_window),
617                   False, NoEventMask, &xevent);
618       gdk_flush ();
619       gdk_error_trap_pop ();
620       
621       return TRUE;
622     }
623   else
624     return FALSE;
625 }
626
627 static gboolean
628 gtk_socket_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
629 {
630   GtkSocket *socket = GTK_SOCKET (widget);
631
632   if (!GTK_WIDGET_HAS_FOCUS (widget))
633     {
634       GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
635   
636       if (socket->plug_window)
637         {
638           send_xembed_message (socket, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT, 0, 0,
639                                gtk_get_current_event_time ());
640         }
641     }
642   
643   return TRUE;
644 }
645
646 static gboolean
647 gtk_socket_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
648 {
649   GtkSocket *socket = GTK_SOCKET (widget);
650
651   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
652
653 #if 0
654   GtkWidget *toplevel;
655   toplevel = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
656   
657   if (toplevel)
658     {
659       XSetInputFocus (GDK_DISPLAY (),
660                       GDK_WINDOW_XWINDOW (toplevel->window),
661                       RevertToParent, CurrentTime); /* FIXME? */
662     }
663
664 #endif      
665
666   if (socket->plug_window)
667     {
668       send_xembed_message (socket, XEMBED_FOCUS_OUT, 0, 0, 0,
669                            gtk_get_current_event_time ());
670     }
671
672   socket->focus_in = FALSE;
673   
674   return TRUE;
675 }
676
677 static void
678 gtk_socket_claim_focus (GtkSocket *socket)
679 {
680       
681   socket->focus_in = TRUE;
682   
683   /* Oh, the trickery... */
684   
685   GTK_WIDGET_SET_FLAGS (socket, GTK_CAN_FOCUS);
686   gtk_widget_grab_focus (GTK_WIDGET (socket));
687   GTK_WIDGET_UNSET_FLAGS (socket, GTK_CAN_FOCUS);
688   
689   /* FIXME: we might grab the focus even if we don't have
690    * it as an app... (and see _focus_in ()) */
691   if (socket->plug_window)
692     {
693 #if 0      
694       gdk_error_trap_push ();
695       XSetInputFocus (GDK_DISPLAY (),
696                       GDK_WINDOW_XWINDOW (socket->plug_window),
697                       RevertToParent, GDK_CURRENT_TIME);
698       gdk_flush ();
699       gdk_error_trap_pop ();
700 #endif
701     }
702 }
703
704 static gboolean
705 gtk_socket_focus (GtkWidget *widget, GtkDirectionType direction)
706 {
707   GtkSocket *socket;
708   gint detail = -1;
709
710   g_return_val_if_fail (GTK_IS_SOCKET (widget), FALSE);
711   
712   socket = GTK_SOCKET (widget);
713
714   if (!GTK_WIDGET_HAS_FOCUS (widget))
715     {
716       switch (direction)
717         {
718         case GTK_DIR_UP:
719         case GTK_DIR_LEFT:
720         case GTK_DIR_TAB_BACKWARD:
721           detail = XEMBED_FOCUS_LAST;
722           break;
723         case GTK_DIR_DOWN:
724         case GTK_DIR_RIGHT:
725         case GTK_DIR_TAB_FORWARD:
726           detail = XEMBED_FOCUS_FIRST;
727           break;
728         }
729       
730       send_xembed_message (socket, XEMBED_FOCUS_IN, detail, 0, 0,
731                            gtk_get_current_event_time ());
732
733       GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
734       gtk_widget_grab_focus (widget);
735  
736       return TRUE;
737     }
738   else
739     return FALSE;
740
741 #if 0
742   if (!socket->focus_in && socket->plug_window)
743     {
744       XEvent xevent;
745
746       gtk_socket_claim_focus (socket);
747       
748       xevent.xkey.type = KeyPress;
749       xevent.xkey.display = GDK_DISPLAY ();
750       xevent.xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
751       xevent.xkey.root = GDK_ROOT_WINDOW (); /* FIXME */
752       xevent.xkey.time = GDK_CURRENT_TIME; /* FIXME */
753       /* FIXME, the following might cause big problems for
754        * non-GTK apps */
755       xevent.xkey.x = 0;
756       xevent.xkey.y = 0;
757       xevent.xkey.x_root = 0;
758       xevent.xkey.y_root = 0;
759       xevent.xkey.state = 0;
760       xevent.xkey.same_screen = TRUE; /* FIXME ? */
761
762       switch (direction)
763         {
764         case GTK_DIR_UP:
765           xevent.xkey.keycode =  XKeysymToKeycode(GDK_DISPLAY(), GDK_Up);
766           break;
767         case GTK_DIR_DOWN:
768           xevent.xkey.keycode =  XKeysymToKeycode(GDK_DISPLAY(), GDK_Down);
769           break;
770         case GTK_DIR_LEFT:
771           xevent.xkey.keycode =  XKeysymToKeycode(GDK_DISPLAY(), GDK_Left);
772           break;
773         case GTK_DIR_RIGHT:
774           xevent.xkey.keycode =  XKeysymToKeycode(GDK_DISPLAY(), GDK_Right);
775           break;
776         case GTK_DIR_TAB_FORWARD:
777           xevent.xkey.keycode =  XKeysymToKeycode(GDK_DISPLAY(), GDK_Tab);
778           break;
779         case GTK_DIR_TAB_BACKWARD:
780           xevent.xkey.keycode =  XKeysymToKeycode(GDK_DISPLAY(), GDK_Tab);
781           xevent.xkey.state = ShiftMask;
782           break;
783         }
784
785
786       gdk_error_trap_push ();
787       XSendEvent (gdk_display,
788                   GDK_WINDOW_XWINDOW (socket->plug_window),
789                   False, NoEventMask, &xevent);
790       gdk_flush();
791       gdk_error_trap_pop ();
792       
793       return TRUE;
794     }
795   else
796     {
797       return FALSE;
798     }
799 #endif  
800 }
801
802 static void
803 gtk_socket_send_configure_event (GtkSocket *socket)
804 {
805   XEvent event;
806
807   g_return_if_fail (socket->plug_window != NULL);
808
809   event.xconfigure.type = ConfigureNotify;
810   event.xconfigure.display = gdk_display;
811
812   event.xconfigure.event = GDK_WINDOW_XWINDOW (socket->plug_window);
813   event.xconfigure.window = GDK_WINDOW_XWINDOW (socket->plug_window);
814
815   event.xconfigure.x = 0;
816   event.xconfigure.y = 0;
817   event.xconfigure.width = GTK_WIDGET(socket)->allocation.width;
818   event.xconfigure.height = GTK_WIDGET(socket)->allocation.height;
819
820   event.xconfigure.border_width = 0;
821   event.xconfigure.above = None;
822   event.xconfigure.override_redirect = False;
823
824   gdk_error_trap_push ();
825   XSendEvent (gdk_display,
826               GDK_WINDOW_XWINDOW (socket->plug_window),
827               False, NoEventMask, &event);
828   gdk_flush ();
829   gdk_error_trap_pop ();
830 }
831
832 static void
833 gtk_socket_add_window (GtkSocket *socket, GdkNativeWindow xid)
834 {
835   socket->plug_window = gdk_window_lookup (xid);
836   socket->same_app = TRUE;
837
838   if (!socket->plug_window)
839     {
840       GtkWidget *toplevel;
841       GdkDragProtocol protocol;
842       
843       socket->plug_window = gdk_window_foreign_new (xid);
844       if (!socket->plug_window) /* Already gone */
845         return;
846         
847       socket->same_app = FALSE;
848
849       gdk_error_trap_push ();
850       XSelectInput (GDK_DISPLAY (),
851                     GDK_WINDOW_XWINDOW(socket->plug_window),
852                     StructureNotifyMask | PropertyChangeMask);
853       
854       if (gdk_drag_get_protocol (xid, &protocol))
855         gtk_drag_dest_set_proxy (GTK_WIDGET (socket), socket->plug_window, 
856                                  protocol, TRUE);
857       gdk_flush ();
858       gdk_error_trap_pop ();
859
860       gdk_window_add_filter (socket->plug_window, 
861                              gtk_socket_filter_func, socket);
862
863       /* Add a pointer to the socket on our toplevel window */
864
865       toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
866       if (toplevel && GTK_IS_WINDOW (toplevel))
867         {
868           gtk_window_add_embedded_xid (GTK_WINDOW (toplevel), xid);
869         }
870
871       gtk_widget_queue_resize (GTK_WIDGET (socket));
872     }
873 }
874
875
876 static void
877 send_xembed_message (GtkSocket *socket,
878                      glong      message,
879                      glong      detail,
880                      glong      data1,
881                      glong      data2,
882                      guint32    time)
883 {
884   GTK_NOTE(PLUGSOCKET,
885            g_message ("GtkSocket: Sending XEMBED message of type %d", message));
886   
887   if (socket->plug_window)
888     {
889       XEvent xevent;
890
891       xevent.xclient.window = GDK_WINDOW_XWINDOW (socket->plug_window);
892       xevent.xclient.type = ClientMessage;
893       xevent.xclient.message_type = gdk_atom_intern ("_XEMBED", FALSE);
894       xevent.xclient.format = 32;
895       xevent.xclient.data.l[0] = time;
896       xevent.xclient.data.l[1] = message;
897       xevent.xclient.data.l[2] = detail;
898       xevent.xclient.data.l[3] = data1;
899       xevent.xclient.data.l[4] = data2;
900
901       gdk_error_trap_push ();
902       XSendEvent (gdk_display,
903                   GDK_WINDOW_XWINDOW (socket->plug_window),
904                   False, NoEventMask, &xevent);
905       gdk_flush ();
906       gdk_error_trap_pop ();
907     }
908 }
909
910 static void
911 handle_xembed_message (GtkSocket *socket,
912                        glong      message,
913                        glong      detail,
914                        glong      data1,
915                        glong      data2,
916                        guint32    time)
917 {
918   switch (message)
919     {
920     case XEMBED_EMBEDDED_NOTIFY:
921     case XEMBED_WINDOW_ACTIVATE:
922     case XEMBED_WINDOW_DEACTIVATE:
923     case XEMBED_MODALITY_ON:
924     case XEMBED_MODALITY_OFF:
925     case XEMBED_FOCUS_IN:
926     case XEMBED_FOCUS_OUT:
927       g_warning ("GtkSocket: Invalid _XEMBED message of type %ld received", message);
928       break;
929       
930     case XEMBED_REQUEST_FOCUS:
931       gtk_socket_claim_focus (socket);
932       break;
933
934     case XEMBED_FOCUS_NEXT:
935     case XEMBED_FOCUS_PREV:
936       {
937         GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
938         if (toplevel)
939           {
940             gtk_widget_child_focus (toplevel,
941                                     (message == XEMBED_FOCUS_NEXT ?
942                                      GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD));
943           }
944         break;
945       }
946       
947     case XEMBED_GRAB_KEY:
948 #if 0
949       add_grabbed_key (socket, data1, data2);
950 #endif
951       break; 
952     case XEMBED_UNGRAB_KEY:
953 #if 0      
954       remove_grabbed_key (socket, data1, data2);
955 #endif
956       break;
957       
958     default:
959       GTK_NOTE(PLUGSOCKET,
960                g_message ("GtkSocket: Ignoring unknown _XEMBED message of type %ld", message));
961       break;
962     }
963 }
964
965 static GdkFilterReturn
966 gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
967 {
968   GtkSocket *socket;
969   GtkWidget *widget;
970   XEvent *xevent;
971
972   GdkFilterReturn return_val;
973   
974   socket = GTK_SOCKET (data);
975   widget = GTK_WIDGET (socket);
976   xevent = (XEvent *)gdk_xevent;
977
978   return_val = GDK_FILTER_CONTINUE;
979
980   switch (xevent->type)
981     {
982     case CreateNotify:
983       {
984         XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
985
986         if (!socket->plug_window)
987           {
988             gtk_socket_add_window (socket, xcwe->window);
989
990             gdk_error_trap_push ();
991             gdk_window_move_resize(socket->plug_window,
992                                    0, 0,
993                                    widget->allocation.width, 
994                                    widget->allocation.height);
995             gdk_flush ();
996             gdk_error_trap_pop ();
997         
998             socket->request_width = xcwe->width;
999             socket->request_height = xcwe->height;
1000             socket->have_size = TRUE;
1001
1002             GTK_NOTE(PLUGSOCKET,
1003                      g_message ("GtkSocket - window created with size: %d %d",
1004                                 socket->request_width,
1005                                 socket->request_height));
1006           }
1007         
1008         return_val = GDK_FILTER_REMOVE;
1009         
1010         break;
1011       }
1012
1013     case ConfigureRequest:
1014       {
1015         XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
1016         
1017         if (!socket->plug_window)
1018           gtk_socket_add_window (socket, xcre->window);
1019         
1020         if (xcre->window == GDK_WINDOW_XWINDOW (socket->plug_window))
1021           {
1022             if (xcre->value_mask & (CWWidth | CWHeight))
1023               {
1024                 socket->request_width = xcre->width;
1025                 socket->request_height = xcre->height;
1026                 socket->have_size = TRUE;
1027                 
1028                 GTK_NOTE(PLUGSOCKET,
1029                          g_message ("GtkSocket - configure request: %d %d",
1030                                     socket->request_width,
1031                                     socket->request_height));
1032                 
1033                 gtk_widget_queue_resize (widget);
1034               }
1035             else if (xcre->value_mask & (CWX | CWY))
1036               {
1037                 gtk_socket_send_configure_event (socket);
1038               }
1039             /* Ignore stacking requests. */
1040             
1041             return_val = GDK_FILTER_REMOVE;
1042           }
1043         break;
1044       }
1045
1046     case DestroyNotify:
1047       {
1048         XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
1049
1050         if (socket->plug_window &&
1051             (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window)))
1052           {
1053             GtkWidget *toplevel;
1054
1055             GTK_NOTE(PLUGSOCKET,
1056                      g_message ("GtkSocket - destroy notify"));
1057             
1058             toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
1059             if (toplevel && GTK_IS_WINDOW (toplevel))
1060               gtk_window_remove_embedded_xid (GTK_WINDOW (toplevel), xdwe->window);
1061             
1062             gdk_window_destroy_notify (socket->plug_window);
1063             gtk_widget_destroy (widget);
1064
1065             socket->plug_window = NULL;
1066             
1067             return_val = GDK_FILTER_REMOVE;
1068           }
1069         break;
1070       }
1071
1072     case FocusIn:
1073       if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
1074         {
1075           gtk_socket_claim_focus (socket);
1076         }
1077       else if (xevent->xfocus.detail == NotifyInferior)
1078         {
1079 #if 0
1080           GtkWidget *toplevel;
1081           toplevel = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
1082           
1083           if (toplevel)
1084             {
1085               XSetInputFocus (GDK_DISPLAY (),
1086                               GDK_WINDOW_XWINDOW (toplevel->window),
1087                               RevertToParent, CurrentTime); /* FIXME? */
1088             }
1089 #endif
1090         }
1091       return_val = GDK_FILTER_REMOVE;
1092       break;
1093     case FocusOut:
1094       return_val = GDK_FILTER_REMOVE;
1095       break;
1096     case MapRequest:
1097       if (!socket->plug_window)
1098         gtk_socket_add_window (socket, xevent->xmaprequest.window);
1099         
1100       if (xevent->xmaprequest.window ==
1101           GDK_WINDOW_XWINDOW (socket->plug_window))
1102         {
1103           GTK_NOTE(PLUGSOCKET,
1104                    g_message ("GtkSocket - Map Request"));
1105           
1106           gdk_error_trap_push ();
1107           gdk_window_show (socket->plug_window);
1108           gdk_flush ();
1109           gdk_error_trap_pop ();
1110
1111           return_val = GDK_FILTER_REMOVE;
1112         }
1113       break;
1114     case PropertyNotify:
1115       if (xevent->xproperty.window ==
1116           GDK_WINDOW_XWINDOW (socket->plug_window))
1117         {
1118           GdkDragProtocol protocol;
1119
1120           if ((xevent->xproperty.atom == gdk_atom_intern ("XdndAware", FALSE)) ||
1121               (xevent->xproperty.atom == gdk_atom_intern ("_MOTIF_DRAG_RECEIVER_INFO", FALSE)))
1122             {
1123               gdk_error_trap_push ();
1124               if (gdk_drag_get_protocol (xevent->xproperty.window, &protocol))
1125                 gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
1126                                          socket->plug_window,
1127                                          protocol, TRUE);
1128               gdk_flush ();
1129               gdk_error_trap_pop ();
1130             }
1131           return_val = GDK_FILTER_REMOVE;
1132         }
1133       break;
1134     case ClientMessage:
1135       if (xevent->xclient.message_type == gdk_atom_intern ("_XEMBED", FALSE))
1136         {
1137           handle_xembed_message (socket,
1138                                  xevent->xclient.data.l[1],
1139                                  xevent->xclient.data.l[2],
1140                                  xevent->xclient.data.l[3],
1141                                  xevent->xclient.data.l[4],
1142                                  xevent->xclient.data.l[0]);
1143           
1144           
1145           return_val = GDK_FILTER_REMOVE;
1146         }
1147       break;
1148     }
1149   
1150   return return_val;
1151 }