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