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