]> Pileus Git - ~andy/gtk/blob - gtk/gtkplug.c
Doc fixes.
[~andy/gtk] / gtk / gtkplug.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 "gtkmain.h"
29 #include "gtkmarshalers.h"
30 #include "gtkplug.h"
31 #include "gtkprivate.h"
32
33 #include "gdk/gdkkeysyms.h"
34 #include "x11/gdkx.h"
35
36 #include "xembed.h"
37
38 static void            gtk_plug_class_init            (GtkPlugClass     *klass);
39 static void            gtk_plug_init                  (GtkPlug          *plug);
40 static void            gtk_plug_finalize              (GObject          *object);
41 static void            gtk_plug_realize               (GtkWidget        *widget);
42 static void            gtk_plug_unrealize             (GtkWidget        *widget);
43 static void            gtk_plug_show                  (GtkWidget        *widget);
44 static void            gtk_plug_hide                  (GtkWidget        *widget);
45 static void            gtk_plug_map                   (GtkWidget        *widget);
46 static void            gtk_plug_unmap                 (GtkWidget        *widget);
47 static void            gtk_plug_size_allocate         (GtkWidget        *widget,
48                                                        GtkAllocation    *allocation);
49 static gboolean        gtk_plug_key_press_event       (GtkWidget        *widget,
50                                                        GdkEventKey      *event);
51 static void            gtk_plug_set_focus             (GtkWindow        *window,
52                                                        GtkWidget        *focus);
53 static gboolean        gtk_plug_focus                 (GtkWidget        *widget,
54                                                        GtkDirectionType  direction);
55 static void            gtk_plug_check_resize          (GtkContainer     *container);
56 static void            gtk_plug_keys_changed          (GtkWindow        *window);
57 static GdkFilterReturn gtk_plug_filter_func           (GdkXEvent        *gdk_xevent,
58                                                        GdkEvent         *event,
59                                                        gpointer          data);
60
61 static void handle_modality_off        (GtkPlug       *plug);
62 static void send_xembed_message        (GtkPlug       *plug,
63                                         glong          message,
64                                         glong          detail,
65                                         glong          data1,
66                                         glong          data2,
67                                         guint32        time);
68 static void xembed_set_info            (GdkWindow     *window,
69                                         unsigned long  flags);
70
71 /* From Tk */
72 #define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
73   
74 static GtkWindowClass *parent_class = NULL;
75 static GtkBinClass *bin_class = NULL;
76
77 enum {
78   EMBEDDED,
79   LAST_SIGNAL
80 }; 
81
82 static guint plug_signals[LAST_SIGNAL] = { 0 };
83
84 GtkType
85 gtk_plug_get_type ()
86 {
87   static GtkType plug_type = 0;
88
89   if (!plug_type)
90     {
91       static const GTypeInfo plug_info =
92       {
93         sizeof (GtkPlugClass),
94         NULL,           /* base_init */
95         NULL,           /* base_finalize */
96         (GClassInitFunc) gtk_plug_class_init,
97         NULL,           /* class_finalize */
98         NULL,           /* class_data */
99         sizeof (GtkPlug),
100         16,             /* n_preallocs */
101         (GInstanceInitFunc) gtk_plug_init,
102       };
103
104       plug_type = g_type_register_static (GTK_TYPE_WINDOW, "GtkPlug", &plug_info, 0);
105     }
106
107   return plug_type;
108 }
109
110 static void
111 gtk_plug_class_init (GtkPlugClass *class)
112 {
113   GObjectClass *gobject_class = (GObjectClass *)class;
114   GtkWidgetClass *widget_class = (GtkWidgetClass *)class;
115   GtkWindowClass *window_class = (GtkWindowClass *)class;
116   GtkContainerClass *container_class = (GtkContainerClass *)class;
117
118   parent_class = gtk_type_class (GTK_TYPE_WINDOW);
119   bin_class = gtk_type_class (GTK_TYPE_BIN);
120
121   gobject_class->finalize = gtk_plug_finalize;
122   
123   widget_class->realize = gtk_plug_realize;
124   widget_class->unrealize = gtk_plug_unrealize;
125   widget_class->key_press_event = gtk_plug_key_press_event;
126
127   widget_class->show = gtk_plug_show;
128   widget_class->hide = gtk_plug_hide;
129   widget_class->map = gtk_plug_map;
130   widget_class->unmap = gtk_plug_unmap;
131   widget_class->size_allocate = gtk_plug_size_allocate;
132
133   widget_class->focus = gtk_plug_focus;
134
135   container_class->check_resize = gtk_plug_check_resize;
136
137   window_class->set_focus = gtk_plug_set_focus;
138   window_class->keys_changed = gtk_plug_keys_changed;
139
140   plug_signals[EMBEDDED] =
141     g_signal_new ("embedded",
142                   G_OBJECT_CLASS_TYPE (class),
143                   G_SIGNAL_RUN_LAST,
144                   G_STRUCT_OFFSET (GtkPlugClass, embedded),
145                   NULL, NULL,
146                   _gtk_marshal_VOID__VOID,
147                   GTK_TYPE_NONE, 0);
148 }
149
150 static void
151 gtk_plug_init (GtkPlug *plug)
152 {
153   GtkWindow *window;
154
155   window = GTK_WINDOW (plug);
156
157   window->type = GTK_WINDOW_TOPLEVEL;
158 }
159
160 static void
161 gtk_plug_set_is_child (GtkPlug  *plug,
162                        gboolean  is_child)
163 {
164   g_assert (!GTK_WIDGET (plug)->parent);
165       
166   if (is_child)
167     {
168       if (plug->modality_window)
169         handle_modality_off (plug);
170
171       if (plug->modality_group)
172         {
173           gtk_window_group_remove_window (plug->modality_group, GTK_WINDOW (plug));
174           g_object_unref (plug->modality_group);
175           plug->modality_group = NULL;
176         }
177       
178       /* As a toplevel, the MAPPED flag doesn't correspond
179        * to whether the widget->window is mapped; we unmap
180        * here, but don't bother remapping -- we will get mapped
181        * by gtk_widget_set_parent ().
182        */
183       if (GTK_WIDGET_MAPPED (plug))
184         gtk_widget_unmap (GTK_WIDGET (plug));
185       
186       GTK_WIDGET_UNSET_FLAGS (plug, GTK_TOPLEVEL);
187       gtk_container_set_resize_mode (GTK_CONTAINER (plug), GTK_RESIZE_PARENT);
188
189       _gtk_widget_propagate_hierarchy_changed (GTK_WIDGET (plug), GTK_WIDGET (plug));
190     }
191   else
192     {
193       if (GTK_WINDOW (plug)->focus_widget)
194         gtk_window_set_focus (GTK_WINDOW (plug), NULL);
195       if (GTK_WINDOW (plug)->default_widget)
196         gtk_window_set_default (GTK_WINDOW (plug), NULL);
197           
198       plug->modality_group = gtk_window_group_new ();
199       gtk_window_group_add_window (plug->modality_group, GTK_WINDOW (plug));
200       
201       GTK_WIDGET_SET_FLAGS (plug, GTK_TOPLEVEL);
202       gtk_container_set_resize_mode (GTK_CONTAINER (plug), GTK_RESIZE_QUEUE);
203
204       _gtk_widget_propagate_hierarchy_changed (GTK_WIDGET (plug), NULL);
205     }
206 }
207
208 /**
209  * _gtk_plug_add_to_socket:
210  * @plug: a #GtkPlug
211  * @socket: a #GtkSocket
212  * 
213  * Adds a plug to a socket within the same application.
214  **/
215 void
216 _gtk_plug_add_to_socket (GtkPlug   *plug,
217                          GtkSocket *socket)
218 {
219   GtkWidget *widget;
220   gint w, h;
221   
222   g_return_if_fail (GTK_IS_PLUG (plug));
223   g_return_if_fail (GTK_IS_SOCKET (socket));
224   g_return_if_fail (GTK_WIDGET_REALIZED (socket));
225
226   widget = GTK_WIDGET (plug);
227
228   gtk_plug_set_is_child (plug, TRUE);
229   plug->same_app = TRUE;
230   socket->same_app = TRUE;
231   socket->plug_widget = widget;
232
233   plug->socket_window = GTK_WIDGET (socket)->window;
234
235   if (GTK_WIDGET_REALIZED (widget))
236     {
237       gdk_drawable_get_size (GDK_DRAWABLE (widget->window), &w, &h);
238       gdk_window_reparent (widget->window, plug->socket_window, -w, -h);
239     }
240
241   gtk_widget_set_parent (widget, GTK_WIDGET (socket));
242
243   g_signal_emit_by_name (G_OBJECT (socket), "plug_added", 0);
244 }
245
246 /**
247  * _gtk_plug_remove_from_socket:
248  * @plug: a #GtkPlug
249  * @socket: a #GtkSocket
250  * 
251  * Removes a plug from a socket within the same application.
252  **/
253 void
254 _gtk_plug_remove_from_socket (GtkPlug   *plug,
255                               GtkSocket *socket)
256 {
257   GtkWidget *widget;
258   GdkEvent event;
259   gboolean result;
260   gboolean widget_was_visible;
261
262   g_return_if_fail (GTK_IS_PLUG (plug));
263   g_return_if_fail (GTK_IS_SOCKET (socket));
264   g_return_if_fail (GTK_WIDGET_REALIZED (plug));
265
266   widget = GTK_WIDGET (plug);
267
268   g_object_ref (plug);
269   g_object_ref (socket);
270
271   widget_was_visible = GTK_WIDGET_VISIBLE (plug);
272   
273   gdk_window_hide (widget->window);
274   gdk_window_reparent (widget->window,
275                        gtk_widget_get_root_window (widget),
276                        0, 0);
277
278   GTK_PRIVATE_SET_FLAG (plug, GTK_IN_REPARENT);
279   gtk_widget_unparent (GTK_WIDGET (plug));
280   GTK_PRIVATE_UNSET_FLAG (plug, GTK_IN_REPARENT);
281   
282   socket->plug_widget = NULL;
283   socket->plug_window = NULL;
284   socket->same_app = FALSE;
285
286   plug->same_app = FALSE;
287   plug->socket_window = NULL;
288
289   gtk_plug_set_is_child (plug, FALSE);
290                     
291   g_signal_emit_by_name (G_OBJECT (socket), "plug_removed", &result);
292   if (!result)
293     gtk_widget_destroy (GTK_WIDGET (socket));
294
295   event.any.type = GDK_DELETE;
296   event.any.window = g_object_ref (widget->window);
297   event.any.send_event = FALSE;
298   
299   if (!gtk_widget_event (widget, &event))
300     gtk_widget_destroy (widget);
301   
302   g_object_unref (event.any.window);
303   g_object_unref (plug);
304
305   if (widget_was_visible && GTK_WIDGET_VISIBLE (socket))
306     gtk_widget_queue_resize (GTK_WIDGET (socket));
307
308   g_object_unref (socket);
309 }
310
311 /**
312  * gtk_plug_construct:
313  * @plug: a #GtkPlug.
314  * @socket_id: the XID of the socket's window.
315  *
316  * Finish the Initialization of @plug for a given #GtkSocket identified by
317  * @socket_id. This function will generally only be used by classes deriving from #GtkPlug.
318  **/
319 void
320 gtk_plug_construct (GtkPlug         *plug,
321                     GdkNativeWindow  socket_id)
322 {
323   gtk_plug_construct_for_display (gdk_get_default_display (), plug, socket_id);
324 }
325
326 /**
327  * gtk_plug_construct_for_display:
328  * @display: the #GdkDisplay associated with @socket_id's 
329  *           #GtkSocket.
330  * @plug: a #GtkPlug.
331  * @socket_id: the XID of the socket's window.
332  *
333  * Finish the Initialization of @plug for a given #GtkSocket identified by
334  * @socket_id which is currently displayed on @display.
335  * This function will generally only be used by classes deriving from #GtkPlug.
336  **/
337 void
338 gtk_plug_construct_for_display (GdkDisplay      *display,
339                                 GtkPlug         *plug,
340                                 GdkNativeWindow  socket_id)
341 {
342   if (socket_id)
343     {
344       gpointer user_data = NULL;
345
346       plug->socket_window = gdk_window_lookup_for_display (display, socket_id);
347       
348       if (plug->socket_window)
349         gdk_window_get_user_data (plug->socket_window, &user_data);
350       else
351         plug->socket_window = gdk_window_foreign_new_for_display (display, socket_id);
352           
353       if (user_data)
354         {
355           if (GTK_IS_SOCKET (user_data))
356             _gtk_plug_add_to_socket (plug, user_data);
357           else
358             {
359               g_warning (G_STRLOC "Can't create GtkPlug as child of non-GtkSocket");
360               plug->socket_window = NULL;
361             }
362         }
363
364       if (plug->socket_window)
365         g_signal_emit (G_OBJECT (plug), plug_signals[EMBEDDED], 0);
366     }
367 }
368
369 /**
370  * gtk_plug_new:
371  * @socket_id:  the window ID of the socket, or 0.
372  * 
373  * Creates a new plug widget inside the #GtkSocket identified
374  * by @socket_id. If @socket_id is 0, the plug is left "unplugged" and
375  * can later be plugged into a #GtkSocket by  gtk_socket_add_id().
376  * 
377  * Return value: the new #GtkPlug widget.
378  **/
379 GtkWidget*
380 gtk_plug_new (GdkNativeWindow socket_id)
381 {
382   return gtk_plug_new_for_display (gdk_get_default_display (), socket_id);
383 }
384
385 /**
386  * gtk_plug_new_for_display:
387  * @display : the #GdkDisplay on which @socket_id is displayed
388  * @socket_id: the XID of the socket's window.
389  * 
390  * Create a new plug widget inside the GtkSocket identified by socket_id.
391  *
392  * Return value: the new #GtkPlug widget.
393  */
394 GtkWidget*
395 gtk_plug_new_for_display (GdkDisplay      *display,
396                           GdkNativeWindow  socket_id)
397 {
398   GtkPlug *plug;
399
400   plug = GTK_PLUG (gtk_type_new (GTK_TYPE_PLUG));
401   gtk_plug_construct_for_display (display, plug, socket_id);
402   return GTK_WIDGET (plug);
403 }
404
405 /**
406  * gtk_plug_get_id:
407  * @plug: a #GtkPlug.
408  * 
409  * Gets the window ID of a #GtkPlug widget, which can then
410  * be used to embed this window inside another window, for
411  * instance with gtk_socket_add_id().
412  * 
413  * Return value: the window ID for the plug
414  **/
415 GdkNativeWindow
416 gtk_plug_get_id (GtkPlug *plug)
417 {
418   g_return_val_if_fail (GTK_IS_PLUG (plug), 0);
419
420   if (!GTK_WIDGET_REALIZED (plug))
421     gtk_widget_realize (GTK_WIDGET (plug));
422
423   return GDK_WINDOW_XWINDOW (GTK_WIDGET (plug)->window);
424 }
425
426 static void
427 gtk_plug_finalize (GObject *object)
428 {
429   GtkPlug *plug = GTK_PLUG (object);
430
431   if (plug->grabbed_keys)
432     {
433       g_hash_table_destroy (plug->grabbed_keys);
434       plug->grabbed_keys = NULL;
435     }
436   
437   G_OBJECT_CLASS (parent_class)->finalize (object);
438 }
439
440 static void
441 gtk_plug_unrealize (GtkWidget *widget)
442 {
443   GtkPlug *plug;
444
445   g_return_if_fail (GTK_IS_PLUG (widget));
446
447   plug = GTK_PLUG (widget);
448
449   if (plug->socket_window != NULL)
450     {
451       gdk_window_set_user_data (plug->socket_window, NULL);
452       gdk_window_unref (plug->socket_window);
453       plug->socket_window = NULL;
454     }
455
456   if (!plug->same_app)
457     {
458       if (plug->modality_window)
459         handle_modality_off (plug);
460
461       gtk_window_group_remove_window (plug->modality_group, GTK_WINDOW (plug));
462       g_object_unref (plug->modality_group);
463     }
464   
465   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
466     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
467 }
468
469 static void
470 gtk_plug_realize (GtkWidget *widget)
471 {
472   GtkWindow *window;
473   GtkPlug *plug;
474   GdkWindowAttr attributes;
475   gint attributes_mask;
476
477   g_return_if_fail (GTK_IS_PLUG (widget));
478
479   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
480   window = GTK_WINDOW (widget);
481   plug = GTK_PLUG (widget);
482
483   attributes.window_type = GDK_WINDOW_CHILD;    /* XXX GDK_WINDOW_PLUG ? */
484   attributes.title = window->title;
485   attributes.wmclass_name = window->wmclass_name;
486   attributes.wmclass_class = window->wmclass_class;
487   attributes.width = widget->allocation.width;
488   attributes.height = widget->allocation.height;
489   attributes.wclass = GDK_INPUT_OUTPUT;
490
491   /* this isn't right - we should match our parent's visual/colormap.
492    * though that will require handling "foreign" colormaps */
493   attributes.visual = gtk_widget_get_visual (widget);
494   attributes.colormap = gtk_widget_get_colormap (widget);
495   attributes.event_mask = gtk_widget_get_events (widget);
496   attributes.event_mask |= (GDK_EXPOSURE_MASK |
497                             GDK_KEY_PRESS_MASK |
498                             GDK_KEY_RELEASE_MASK |
499                             GDK_ENTER_NOTIFY_MASK |
500                             GDK_LEAVE_NOTIFY_MASK |
501                             GDK_FOCUS_CHANGE_MASK |
502                             GDK_STRUCTURE_MASK);
503
504   attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
505   attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
506   attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
507
508   if (GTK_WIDGET_TOPLEVEL (widget))
509     {
510       attributes.window_type = GDK_WINDOW_TOPLEVEL;
511
512       gdk_error_trap_push ();
513       if (plug->socket_window)
514         widget->window = gdk_window_new (plug->socket_window, 
515                                          &attributes, attributes_mask);
516       else /* If it's a passive plug, we use the root window */
517         widget->window = gdk_window_new (gtk_widget_get_root_window (widget),
518                                          &attributes, attributes_mask);
519
520       gdk_display_sync (gtk_widget_get_display (widget));
521       if (gdk_error_trap_pop ()) /* Uh-oh */
522         {
523           gdk_error_trap_push ();
524           gdk_window_destroy (widget->window);
525           gdk_flush ();
526           gdk_error_trap_pop ();
527           widget->window = gdk_window_new (gtk_widget_get_root_window (widget),
528                                            &attributes, attributes_mask);
529         }
530       
531       gdk_window_add_filter (widget->window, gtk_plug_filter_func, widget);
532
533       plug->modality_group = gtk_window_group_new ();
534       gtk_window_group_add_window (plug->modality_group, window);
535       
536       xembed_set_info (widget->window, 0);
537     }
538   else
539     widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), 
540                                      &attributes, attributes_mask);      
541   
542   gdk_window_set_user_data (widget->window, window);
543
544   widget->style = gtk_style_attach (widget->style, widget->window);
545   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
546 }
547
548 static void
549 gtk_plug_show (GtkWidget *widget)
550 {
551   if (GTK_WIDGET_TOPLEVEL (widget))
552     GTK_WIDGET_CLASS (parent_class)->show (widget);
553   else
554     GTK_WIDGET_CLASS (bin_class)->show (widget);
555 }
556
557 static void
558 gtk_plug_hide (GtkWidget *widget)
559 {
560   if (GTK_WIDGET_TOPLEVEL (widget))
561     GTK_WIDGET_CLASS (parent_class)->hide (widget);
562   else
563     GTK_WIDGET_CLASS (bin_class)->hide (widget);
564 }
565
566 /* From gdkinternals.h */
567 void gdk_synthesize_window_state (GdkWindow     *window,
568                                   GdkWindowState unset_flags,
569                                   GdkWindowState set_flags);
570
571 static void
572 gtk_plug_map (GtkWidget *widget)
573 {
574   if (GTK_WIDGET_TOPLEVEL (widget))
575     {
576       GtkBin *bin = GTK_BIN (widget);
577       
578       GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
579
580       if (bin->child &&
581           GTK_WIDGET_VISIBLE (bin->child) &&
582           !GTK_WIDGET_MAPPED (bin->child))
583         gtk_widget_map (bin->child);
584
585       xembed_set_info (widget->window, XEMBED_MAPPED);
586       
587       gdk_synthesize_window_state (widget->window,
588                                    GDK_WINDOW_STATE_WITHDRAWN,
589                                    0);
590     }
591   else
592     GTK_WIDGET_CLASS (bin_class)->map (widget);
593 }
594
595 static void
596 gtk_plug_unmap (GtkWidget *widget)
597 {
598   if (GTK_WIDGET_TOPLEVEL (widget))
599     {
600       GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
601
602       gdk_window_hide (widget->window);
603       xembed_set_info (widget->window, 0);
604       
605       gdk_synthesize_window_state (widget->window,
606                                    0,
607                                    GDK_WINDOW_STATE_WITHDRAWN);
608     }
609   else
610     GTK_WIDGET_CLASS (bin_class)->unmap (widget);
611 }
612
613 static void
614 gtk_plug_size_allocate (GtkWidget     *widget,
615                         GtkAllocation *allocation)
616 {
617   if (GTK_WIDGET_TOPLEVEL (widget))
618     GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
619   else
620     {
621       GtkBin *bin = GTK_BIN (widget);
622
623       widget->allocation = *allocation;
624
625       if (GTK_WIDGET_REALIZED (widget))
626         gdk_window_move_resize (widget->window,
627                                 allocation->x, allocation->y,
628                                 allocation->width, allocation->height);
629
630       if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
631         {
632           GtkAllocation child_allocation;
633           
634           child_allocation.x = child_allocation.y = GTK_CONTAINER (widget)->border_width;
635           child_allocation.width =
636             MAX (1, (gint)allocation->width - child_allocation.x * 2);
637           child_allocation.height =
638             MAX (1, (gint)allocation->height - child_allocation.y * 2);
639           
640           gtk_widget_size_allocate (bin->child, &child_allocation);
641         }
642       
643     }
644 }
645
646 static gboolean
647 gtk_plug_key_press_event (GtkWidget   *widget,
648                           GdkEventKey *event)
649 {
650   if (GTK_WIDGET_TOPLEVEL (widget))
651     return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
652   else
653     return FALSE;
654 }
655
656 static void
657 gtk_plug_set_focus (GtkWindow *window,
658                     GtkWidget *focus)
659 {
660   GtkPlug *plug = GTK_PLUG (window);
661
662   GTK_WINDOW_CLASS (parent_class)->set_focus (window, focus);
663   
664   /* Ask for focus from embedder
665    */
666
667   if (focus && !window->has_focus)
668     {
669 #if 0      
670       XEvent xevent;
671
672       xevent.xfocus.type = FocusIn;
673       xevent.xfocus.display = GDK_WINDOW_XDISPLAY (plug->socket_window);
674       xevent.xfocus.window = GDK_WINDOW_XWINDOW (plug->socket_window);
675       xevent.xfocus.mode = EMBEDDED_APP_WANTS_FOCUS;
676       xevent.xfocus.detail = FALSE; /* Don't force */
677
678       gdk_error_trap_push ();
679       XSendEvent (GDK_DISPLAY (),
680                   GDK_WINDOW_XWINDOW (plug->socket_window),
681                   False, NoEventMask, &xevent);
682       gdk_display_sync (gdk_drawable_get_display (plug->socket_window));
683       gdk_error_trap_pop ();
684 #endif
685
686       send_xembed_message (plug, XEMBED_REQUEST_FOCUS, 0, 0, 0,
687                            gtk_get_current_event_time ());
688     }
689 }
690
691 typedef struct
692 {
693   guint                  accelerator_key;
694   GdkModifierType        accelerator_mods;
695 } GrabbedKey;
696
697 static guint
698 grabbed_key_hash (gconstpointer a)
699 {
700   const GrabbedKey *key = a;
701   guint h;
702   
703   h = key->accelerator_key << 16;
704   h ^= key->accelerator_key >> 16;
705   h ^= key->accelerator_mods;
706
707   return h;
708 }
709
710 static gboolean
711 grabbed_key_equal (gconstpointer a, gconstpointer b)
712 {
713   const GrabbedKey *keya = a;
714   const GrabbedKey *keyb = b;
715
716   return (keya->accelerator_key == keyb->accelerator_key &&
717           keya->accelerator_mods == keyb->accelerator_mods);
718 }
719
720 static void
721 add_grabbed_key (gpointer key, gpointer val, gpointer data)
722 {
723   GrabbedKey *grabbed_key = key;
724   GtkPlug *plug = data;
725
726   if (!plug->grabbed_keys ||
727       !g_hash_table_lookup (plug->grabbed_keys, grabbed_key))
728     {
729       send_xembed_message (plug, XEMBED_GTK_GRAB_KEY, 0, 
730                            grabbed_key->accelerator_key, grabbed_key->accelerator_mods,
731                            gtk_get_current_event_time ());
732     }
733 }
734
735 static void
736 add_grabbed_key_always (gpointer key, gpointer val, gpointer data)
737 {
738   GrabbedKey *grabbed_key = key;
739   GtkPlug *plug = data;
740
741   send_xembed_message (plug, XEMBED_GTK_GRAB_KEY, 0, 
742                        grabbed_key->accelerator_key, grabbed_key->accelerator_mods,
743                        gtk_get_current_event_time ());
744 }
745
746 static void
747 remove_grabbed_key (gpointer key, gpointer val, gpointer data)
748 {
749   GrabbedKey *grabbed_key = key;
750   GtkPlug *plug = data;
751
752   if (!plug->grabbed_keys ||
753       !g_hash_table_lookup (plug->grabbed_keys, grabbed_key))
754     {
755       send_xembed_message (plug, XEMBED_GTK_UNGRAB_KEY, 0, 
756                            grabbed_key->accelerator_key, grabbed_key->accelerator_mods,
757                            gtk_get_current_event_time ());
758     }
759 }
760
761 static void
762 keys_foreach (GtkWindow      *window,
763               guint           keyval,
764               GdkModifierType modifiers,
765               gboolean        is_mnemonic,
766               gpointer        data)
767 {
768   GHashTable *new_grabbed_keys = data;
769   GrabbedKey *key = g_new (GrabbedKey, 1);
770
771   key->accelerator_key = keyval;
772   key->accelerator_mods = modifiers;
773   
774   g_hash_table_replace (new_grabbed_keys, key, key);
775 }
776
777 static void
778 gtk_plug_keys_changed (GtkWindow *window)
779 {
780   GHashTable *new_grabbed_keys, *old_grabbed_keys;
781   GtkPlug *plug = GTK_PLUG (window);
782
783   new_grabbed_keys = g_hash_table_new_full (grabbed_key_hash, grabbed_key_equal, (GDestroyNotify)g_free, NULL);
784   _gtk_window_keys_foreach (window, keys_foreach, new_grabbed_keys);
785
786   if (plug->socket_window)
787     g_hash_table_foreach (new_grabbed_keys, add_grabbed_key, plug);
788
789   old_grabbed_keys = plug->grabbed_keys;
790   plug->grabbed_keys = new_grabbed_keys;
791
792   if (old_grabbed_keys)
793     {
794       if (plug->socket_window)
795         g_hash_table_foreach (old_grabbed_keys, remove_grabbed_key, plug);
796       g_hash_table_destroy (old_grabbed_keys);
797     }
798 }
799
800 static gboolean
801 gtk_plug_focus (GtkWidget        *widget,
802                 GtkDirectionType  direction)
803 {
804   GtkBin *bin = GTK_BIN (widget);
805   GtkPlug *plug = GTK_PLUG (widget);
806   GtkWindow *window = GTK_WINDOW (widget);
807   GtkContainer *container = GTK_CONTAINER (widget);
808   GtkWidget *old_focus_child = container->focus_child;
809   GtkWidget *parent;
810   
811   /* We override GtkWindow's behavior, since we don't want wrapping here.
812    */
813   if (old_focus_child)
814     {
815       if (gtk_widget_child_focus (old_focus_child, direction))
816         return TRUE;
817
818       if (window->focus_widget)
819         {
820           /* Wrapped off the end, clear the focus setting for the toplevel */
821           parent = window->focus_widget->parent;
822           while (parent)
823             {
824               gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
825               parent = GTK_WIDGET (parent)->parent;
826             }
827           
828           gtk_window_set_focus (GTK_WINDOW (container), NULL);
829
830           if (!GTK_CONTAINER (window)->focus_child)
831             {
832               gint message = -1;
833
834               switch (direction)
835                 {
836                 case GTK_DIR_UP:
837                 case GTK_DIR_LEFT:
838                 case GTK_DIR_TAB_BACKWARD:
839                   message = XEMBED_FOCUS_PREV;
840                   break;
841                 case GTK_DIR_DOWN:
842                 case GTK_DIR_RIGHT:
843                 case GTK_DIR_TAB_FORWARD:
844                   message = XEMBED_FOCUS_NEXT;
845                   break;
846                 }
847               
848               send_xembed_message (plug, message, 0, 0, 0,
849                                    gtk_get_current_event_time ());
850               
851 #if 0         
852               gtk_window_set_focus (GTK_WINDOW (widget), NULL);
853
854               gdk_error_trap_push ();
855               XSetInputFocus (GDK_WINDOW_XDISPLAY (plug->socket_window),
856                               GDK_WINDOW_XWINDOW (plug->socket_window),
857                               RevertToParent, event->time);
858               gdk_display_sync (gdk_drawable_get_display (plug->socket_window));
859               gdk_error_trap_pop ();
860
861               gtk_plug_forward_key_press (plug, event);
862 #endif        
863             }
864         }
865
866       return FALSE;
867     }
868   else
869     {
870       /* Try to focus the first widget in the window */
871       
872       if (bin->child && gtk_widget_child_focus (bin->child, direction))
873         return TRUE;
874     }
875
876   return FALSE;
877 }
878
879 static void
880 gtk_plug_check_resize (GtkContainer *container)
881 {
882   if (GTK_WIDGET_TOPLEVEL (container))
883     GTK_CONTAINER_CLASS (parent_class)->check_resize (container);
884   else
885     GTK_CONTAINER_CLASS (bin_class)->check_resize (container);
886 }
887
888 static void
889 send_xembed_message (GtkPlug *plug,
890                      glong      message,
891                      glong      detail,
892                      glong      data1,
893                      glong      data2,
894                      guint32    time)
895 {
896   if (plug->socket_window)
897     {
898       GdkDisplay *display = gdk_drawable_get_display (plug->socket_window);
899       XEvent xevent;
900
901       xevent.xclient.window = GDK_WINDOW_XWINDOW (plug->socket_window);
902       xevent.xclient.type = ClientMessage;
903       xevent.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED");
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_WINDOW_XDISPLAY(plug->socket_window),
913                   GDK_WINDOW_XWINDOW (plug->socket_window),
914                   False, NoEventMask, &xevent);
915       gdk_display_sync (display);
916       gdk_error_trap_pop ();
917     }
918 }
919
920 static void
921 focus_first_last (GtkPlug          *plug,
922                   GtkDirectionType  direction)
923 {
924   GtkWindow *window = GTK_WINDOW (plug);
925   GtkWidget *parent;
926   
927   if (window->focus_widget)
928     {
929       parent = window->focus_widget->parent;
930       while (parent)
931         {
932           gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
933           parent = GTK_WIDGET (parent)->parent;
934         }
935       
936       gtk_window_set_focus (GTK_WINDOW (plug), NULL);
937     }
938
939   gtk_widget_child_focus (GTK_WIDGET (plug), direction);
940 }
941
942 static void
943 handle_modality_on (GtkPlug *plug)
944 {
945   if (!plug->modality_window)
946     {
947       plug->modality_window = gtk_window_new (GTK_WINDOW_POPUP);
948       gtk_window_set_screen (GTK_WINDOW (plug->modality_window),
949                              gtk_widget_get_screen (GTK_WIDGET (plug)));
950       gtk_widget_realize (plug->modality_window);
951       gtk_window_group_add_window (plug->modality_group, GTK_WINDOW (plug->modality_window));
952       gtk_grab_add (plug->modality_window);
953     }
954 }
955
956 static void
957 handle_modality_off (GtkPlug *plug)
958 {
959   if (plug->modality_window)
960     {
961       gtk_widget_destroy (plug->modality_window);
962       plug->modality_window = NULL;
963     }
964 }
965
966 static void
967 xembed_set_info (GdkWindow     *window,
968                  unsigned long  flags)
969 {
970   GdkDisplay *display = gdk_drawable_get_display (window);
971   unsigned long buffer[2];
972
973   Atom xembed_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO");
974
975   buffer[1] = 0;                /* Protocol version */
976   buffer[1] = flags;
977
978   XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
979                    GDK_WINDOW_XWINDOW (window),
980                    xembed_info_atom, xembed_info_atom, 32,
981                    PropModeReplace,
982                    (unsigned char *)buffer, 2);
983 }
984
985 static void
986 handle_xembed_message (GtkPlug   *plug,
987                        glong      message,
988                        glong      detail,
989                        glong      data1,
990                        glong      data2,
991                        guint32    time)
992 {
993   GTK_NOTE (PLUGSOCKET,
994             g_message ("Message of type %ld received", message));
995   
996   switch (message)
997     {
998     case XEMBED_EMBEDDED_NOTIFY:
999       break;
1000     case XEMBED_WINDOW_ACTIVATE:
1001       GTK_NOTE(PLUGSOCKET,
1002                g_message ("GtkPlug: ACTIVATE received"));
1003       break;
1004     case XEMBED_WINDOW_DEACTIVATE:
1005       GTK_NOTE(PLUGSOCKET,
1006                g_message ("GtkPlug: DEACTIVATE received"));
1007       break;
1008       
1009     case XEMBED_MODALITY_ON:
1010       handle_modality_on (plug);
1011       break;
1012     case XEMBED_MODALITY_OFF:
1013       handle_modality_off (plug);
1014       break;
1015
1016     case XEMBED_FOCUS_IN:
1017       switch (detail)
1018         {
1019         case XEMBED_FOCUS_FIRST:
1020           focus_first_last (plug, GTK_DIR_TAB_FORWARD);
1021           break;
1022         case XEMBED_FOCUS_LAST:
1023           focus_first_last (plug, GTK_DIR_TAB_BACKWARD);
1024           break;
1025         case XEMBED_FOCUS_CURRENT:
1026           /* fall through */;
1027         }
1028       
1029     case XEMBED_FOCUS_OUT:
1030       {
1031         GdkEvent event;
1032
1033         event.focus_change.type = GDK_FOCUS_CHANGE;
1034         event.focus_change.window = GTK_WIDGET (plug)->window;
1035         event.focus_change.send_event = TRUE;
1036         event.focus_change.in = (message == XEMBED_FOCUS_IN);
1037
1038         gtk_widget_event (GTK_WIDGET (plug), &event);
1039
1040         break;
1041       }
1042       
1043     case XEMBED_GRAB_KEY:
1044     case XEMBED_UNGRAB_KEY:
1045     case XEMBED_GTK_GRAB_KEY:
1046     case XEMBED_GTK_UNGRAB_KEY:
1047     case XEMBED_REQUEST_FOCUS:
1048     case XEMBED_FOCUS_NEXT:
1049     case XEMBED_FOCUS_PREV:
1050       g_warning ("GtkPlug: Invalid _XEMBED message of type %ld received", message);
1051       break;
1052       
1053     default:
1054       GTK_NOTE(PLUGSOCKET,
1055                g_message ("GtkPlug: Ignoring unknown _XEMBED message of type %ld", message));
1056       break;
1057     }
1058 }
1059
1060 static GdkFilterReturn
1061 gtk_plug_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
1062 {
1063   GdkScreen *screen = gdk_drawable_get_screen (event->any.window);
1064   GdkDisplay *display = gdk_screen_get_display (screen);
1065   GtkPlug *plug = GTK_PLUG (data);
1066   XEvent *xevent = (XEvent *)gdk_xevent;
1067
1068   GdkFilterReturn return_val;
1069   
1070   return_val = GDK_FILTER_CONTINUE;
1071
1072   switch (xevent->type)
1073     {
1074     case ClientMessage:
1075       if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED"))
1076         {
1077           handle_xembed_message (plug,
1078                                  xevent->xclient.data.l[1],
1079                                  xevent->xclient.data.l[2],
1080                                  xevent->xclient.data.l[3],
1081                                  xevent->xclient.data.l[4],
1082                                  xevent->xclient.data.l[0]);
1083                                  
1084
1085           return GDK_FILTER_REMOVE;
1086         }
1087       else if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW"))
1088         {
1089           /* We filter these out because we take being reparented back to the
1090            * root window as the reliable end of the embedding protocol
1091            */
1092
1093           return GDK_FILTER_REMOVE;
1094         }
1095       break;
1096     case ReparentNotify:
1097       {
1098         XReparentEvent *xre = &xevent->xreparent;
1099         gboolean was_embedded = plug->socket_window != NULL;
1100
1101         return_val = GDK_FILTER_REMOVE;
1102         
1103         g_object_ref (plug);
1104         
1105         if (was_embedded)
1106           {
1107             /* End of embedding protocol for previous socket */
1108             
1109             /* FIXME: race if we remove from another socket and
1110              * then add to a local window before we get notification
1111              * Probably need check in _gtk_plug_add_to_socket
1112              */
1113             
1114             if (xre->parent != GDK_WINDOW_XWINDOW (plug->socket_window))
1115               {
1116                 GtkWidget *widget = GTK_WIDGET (plug);
1117
1118                 gdk_window_set_user_data (plug->socket_window, NULL);
1119                 gdk_window_unref (plug->socket_window);
1120                 plug->socket_window = NULL;
1121
1122                 /* Emit a delete window, as if the user attempted
1123                  * to close the toplevel. Simple as to how we
1124                  * handle WM_DELETE_WINDOW, if it isn't handled
1125                  * we destroy the widget. BUt only do this if
1126                  * we are being reparented to the root window.
1127                  * Moving from one embedder to another should
1128                  * be invisible to the app.
1129                  */
1130
1131                 if (xre->parent == GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen)))
1132                   {
1133                     GdkEvent event;
1134                     
1135                     event.any.type = GDK_DELETE;
1136                     event.any.window = g_object_ref (widget->window);
1137                     event.any.send_event = FALSE;
1138                     
1139                     if (!gtk_widget_event (widget, &event))
1140                       gtk_widget_destroy (widget);
1141                     
1142                     g_object_unref (event.any.window);
1143                   }
1144               }
1145             else
1146               break;
1147           }
1148
1149         if (xre->parent != GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen)))
1150           {
1151             /* Start of embedding protocol */
1152
1153             plug->socket_window = gdk_window_lookup_for_display (display, xre->parent);
1154             if (plug->socket_window)
1155               {
1156                 gpointer user_data = NULL;
1157                 gdk_window_get_user_data (plug->socket_window, &user_data);
1158
1159                 if (user_data)
1160                   {
1161                     g_warning (G_STRLOC "Plug reparented unexpectedly into window in the same process");
1162                     plug->socket_window = NULL;
1163                     break;
1164                   }
1165
1166                 g_object_ref (plug->socket_window);
1167               }
1168             else
1169               {
1170                 plug->socket_window = gdk_window_foreign_new_for_display (display, xre->parent);
1171                 if (!plug->socket_window) /* Already gone */
1172                   break;
1173               }
1174
1175             if (plug->grabbed_keys)
1176               g_hash_table_foreach (plug->grabbed_keys, add_grabbed_key_always, plug);
1177
1178             if (!was_embedded)
1179               g_signal_emit (G_OBJECT (plug), plug_signals[EMBEDDED], 0);
1180           }
1181         
1182         g_object_unref (plug);
1183         
1184         break;
1185       }
1186     }
1187
1188   return GDK_FILTER_CONTINUE;
1189 }