]> Pileus Git - ~andy/gtk/blob - gtk/gtkplug.c
Documentation 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 <config.h>
29
30 #include "gtkmain.h"
31 #include "gtkmarshalers.h"
32 #include "gtkplug.h"
33 #include "gtkintl.h"
34 #include "gtkprivate.h"
35 #include "gtkplugprivate.h"
36
37 #include "gtkalias.h"
38
39 static void            gtk_plug_class_init            (GtkPlugClass     *klass);
40 static void            gtk_plug_init                  (GtkPlug          *plug);
41 static void            gtk_plug_finalize              (GObject          *object);
42 static void            gtk_plug_realize               (GtkWidget        *widget);
43 static void            gtk_plug_unrealize             (GtkWidget        *widget);
44 static void            gtk_plug_show                  (GtkWidget        *widget);
45 static void            gtk_plug_hide                  (GtkWidget        *widget);
46 static void            gtk_plug_map                   (GtkWidget        *widget);
47 static void            gtk_plug_unmap                 (GtkWidget        *widget);
48 static void            gtk_plug_size_allocate         (GtkWidget        *widget,
49                                                        GtkAllocation    *allocation);
50 static gboolean        gtk_plug_key_press_event       (GtkWidget        *widget,
51                                                        GdkEventKey      *event);
52 static gboolean        gtk_plug_focus_event           (GtkWidget        *widget,
53                                                        GdkEventFocus    *event);
54 static void            gtk_plug_set_focus             (GtkWindow        *window,
55                                                        GtkWidget        *focus);
56 static gboolean        gtk_plug_focus                 (GtkWidget        *widget,
57                                                        GtkDirectionType  direction);
58 static void            gtk_plug_check_resize          (GtkContainer     *container);
59 static void            gtk_plug_keys_changed          (GtkWindow        *window);
60
61 static GtkWindowClass *parent_class = NULL;
62 static GtkBinClass *bin_class = NULL;
63
64 typedef struct
65 {
66   guint                  accelerator_key;
67   GdkModifierType        accelerator_mods;
68 } GrabbedKey;
69
70 enum {
71   EMBEDDED,
72   LAST_SIGNAL
73 }; 
74
75 static guint plug_signals[LAST_SIGNAL] = { 0 };
76
77 GType
78 gtk_plug_get_type (void)
79 {
80   static GType plug_type = 0;
81
82   if (!plug_type)
83     {
84       static const GTypeInfo plug_info =
85       {
86         sizeof (GtkPlugClass),
87         NULL,           /* base_init */
88         NULL,           /* base_finalize */
89         (GClassInitFunc) gtk_plug_class_init,
90         NULL,           /* class_finalize */
91         NULL,           /* class_data */
92         sizeof (GtkPlug),
93         16,             /* n_preallocs */
94         (GInstanceInitFunc) gtk_plug_init,
95       };
96
97       plug_type = g_type_register_static (GTK_TYPE_WINDOW, I_("GtkPlug"),
98                                           &plug_info, 0);
99     }
100
101   return plug_type;
102 }
103
104 static void
105 gtk_plug_class_init (GtkPlugClass *class)
106 {
107   GObjectClass *gobject_class = (GObjectClass *)class;
108   GtkWidgetClass *widget_class = (GtkWidgetClass *)class;
109   GtkWindowClass *window_class = (GtkWindowClass *)class;
110   GtkContainerClass *container_class = (GtkContainerClass *)class;
111
112   parent_class = g_type_class_peek_parent (class);
113   bin_class = g_type_class_peek (GTK_TYPE_BIN);
114
115   gobject_class->finalize = gtk_plug_finalize;
116   
117   widget_class->realize = gtk_plug_realize;
118   widget_class->unrealize = gtk_plug_unrealize;
119   widget_class->key_press_event = gtk_plug_key_press_event;
120   widget_class->focus_in_event = gtk_plug_focus_event;
121   widget_class->focus_out_event = gtk_plug_focus_event;
122
123   widget_class->show = gtk_plug_show;
124   widget_class->hide = gtk_plug_hide;
125   widget_class->map = gtk_plug_map;
126   widget_class->unmap = gtk_plug_unmap;
127   widget_class->size_allocate = gtk_plug_size_allocate;
128
129   widget_class->focus = gtk_plug_focus;
130
131   container_class->check_resize = gtk_plug_check_resize;
132
133   window_class->set_focus = gtk_plug_set_focus;
134   window_class->keys_changed = gtk_plug_keys_changed;
135
136   plug_signals[EMBEDDED] =
137     g_signal_new (I_("embedded"),
138                   G_OBJECT_CLASS_TYPE (class),
139                   G_SIGNAL_RUN_LAST,
140                   G_STRUCT_OFFSET (GtkPlugClass, embedded),
141                   NULL, NULL,
142                   _gtk_marshal_VOID__VOID,
143                   G_TYPE_NONE, 0);
144 }
145
146 static void
147 gtk_plug_init (GtkPlug *plug)
148 {
149   GtkWindow *window;
150
151   window = GTK_WINDOW (plug);
152
153   window->type = GTK_WINDOW_TOPLEVEL;
154 }
155
156 static void
157 gtk_plug_set_is_child (GtkPlug  *plug,
158                        gboolean  is_child)
159 {
160   g_assert (!GTK_WIDGET (plug)->parent);
161       
162   if (is_child)
163     {
164       if (plug->modality_window)
165         _gtk_plug_handle_modality_off (plug);
166
167       if (plug->modality_group)
168         {
169           gtk_window_group_remove_window (plug->modality_group, GTK_WINDOW (plug));
170           g_object_unref (plug->modality_group);
171           plug->modality_group = NULL;
172         }
173       
174       /* As a toplevel, the MAPPED flag doesn't correspond
175        * to whether the widget->window is mapped; we unmap
176        * here, but don't bother remapping -- we will get mapped
177        * by gtk_widget_set_parent ().
178        */
179       if (GTK_WIDGET_MAPPED (plug))
180         gtk_widget_unmap (GTK_WIDGET (plug));
181       
182       GTK_WIDGET_UNSET_FLAGS (plug, GTK_TOPLEVEL);
183       gtk_container_set_resize_mode (GTK_CONTAINER (plug), GTK_RESIZE_PARENT);
184
185       _gtk_widget_propagate_hierarchy_changed (GTK_WIDGET (plug), GTK_WIDGET (plug));
186     }
187   else
188     {
189       if (GTK_WINDOW (plug)->focus_widget)
190         gtk_window_set_focus (GTK_WINDOW (plug), NULL);
191       if (GTK_WINDOW (plug)->default_widget)
192         gtk_window_set_default (GTK_WINDOW (plug), NULL);
193           
194       plug->modality_group = gtk_window_group_new ();
195       gtk_window_group_add_window (plug->modality_group, GTK_WINDOW (plug));
196       
197       GTK_WIDGET_SET_FLAGS (plug, GTK_TOPLEVEL);
198       gtk_container_set_resize_mode (GTK_CONTAINER (plug), GTK_RESIZE_QUEUE);
199
200       _gtk_widget_propagate_hierarchy_changed (GTK_WIDGET (plug), NULL);
201     }
202 }
203
204 /**
205  * gtk_plug_get_id:
206  * @plug: a #GtkPlug.
207  * 
208  * Gets the window ID of a #GtkPlug widget, which can then
209  * be used to embed this window inside another window, for
210  * instance with gtk_socket_add_id().
211  * 
212  * Return value: the window ID for the plug
213  **/
214 GdkNativeWindow
215 gtk_plug_get_id (GtkPlug *plug)
216 {
217   g_return_val_if_fail (GTK_IS_PLUG (plug), 0);
218
219   if (!GTK_WIDGET_REALIZED (plug))
220     gtk_widget_realize (GTK_WIDGET (plug));
221
222   return _gtk_plug_windowing_get_id (plug);
223 }
224
225 /**
226  * _gtk_plug_add_to_socket:
227  * @plug: a #GtkPlug
228  * @socket_: a #GtkSocket
229  * 
230  * Adds a plug to a socket within the same application.
231  **/
232 void
233 _gtk_plug_add_to_socket (GtkPlug   *plug,
234                          GtkSocket *socket_)
235 {
236   GtkWidget *widget;
237   gint w, h;
238   
239   g_return_if_fail (GTK_IS_PLUG (plug));
240   g_return_if_fail (GTK_IS_SOCKET (socket_));
241   g_return_if_fail (GTK_WIDGET_REALIZED (socket_));
242
243   widget = GTK_WIDGET (plug);
244
245   gtk_plug_set_is_child (plug, TRUE);
246   plug->same_app = TRUE;
247   socket_->same_app = TRUE;
248   socket_->plug_widget = widget;
249
250   plug->socket_window = GTK_WIDGET (socket_)->window;
251
252   if (GTK_WIDGET_REALIZED (widget))
253     {
254       gdk_drawable_get_size (GDK_DRAWABLE (widget->window), &w, &h);
255       gdk_window_reparent (widget->window, plug->socket_window, -w, -h);
256     }
257
258   gtk_widget_set_parent (widget, GTK_WIDGET (socket_));
259
260   g_signal_emit_by_name (socket, "plug_added");
261 }
262
263 /**
264  * _gtk_plug_send_delete_event:
265  * @widget: a #GtkWidget
266  *
267  * Send a GDK_DELETE event to the @widget and destroy it if
268  * necessary. Internal GTK function, called from this file or the
269  * backend-specific GtkPlug implementation.
270  */
271 void
272 _gtk_plug_send_delete_event (GtkWidget *widget)
273 {
274   GdkEvent *event = gdk_event_new (GDK_DELETE);
275   
276   event->any.window = g_object_ref (widget->window);
277   event->any.send_event = FALSE;
278
279   gtk_widget_ref (widget);
280   
281   if (!gtk_widget_event (widget, event))
282     gtk_widget_destroy (widget);
283   
284   gtk_widget_unref (widget);
285
286   gdk_event_free (event);
287 }
288
289 /**
290  * _gtk_plug_remove_from_socket:
291  * @plug: a #GtkPlug
292  * @socket_: a #GtkSocket
293  * 
294  * Removes a plug from a socket within the same application.
295  **/
296 void
297 _gtk_plug_remove_from_socket (GtkPlug   *plug,
298                               GtkSocket *socket_)
299 {
300   GtkWidget *widget;
301   gboolean result;
302   gboolean widget_was_visible;
303
304   g_return_if_fail (GTK_IS_PLUG (plug));
305   g_return_if_fail (GTK_IS_SOCKET (socket_));
306   g_return_if_fail (GTK_WIDGET_REALIZED (plug));
307
308   widget = GTK_WIDGET (plug);
309
310   if (GTK_WIDGET_IN_REPARENT (widget))
311     return;
312
313   g_object_ref (plug);
314   g_object_ref (socket_);
315
316   widget_was_visible = GTK_WIDGET_VISIBLE (plug);
317   
318   gdk_window_hide (widget->window);
319   GTK_PRIVATE_SET_FLAG (plug, GTK_IN_REPARENT);
320   gdk_window_reparent (widget->window,
321                        gtk_widget_get_root_window (widget),
322                        0, 0);
323   gtk_widget_unparent (GTK_WIDGET (plug));
324   GTK_PRIVATE_UNSET_FLAG (plug, GTK_IN_REPARENT);
325   
326   socket_->plug_widget = NULL;
327   if (socket_->plug_window != NULL)
328     {
329       g_object_unref (socket_->plug_window);
330       socket_->plug_window = NULL;
331     }
332   
333   socket_->same_app = FALSE;
334
335   plug->same_app = FALSE;
336   plug->socket_window = NULL;
337
338   gtk_plug_set_is_child (plug, FALSE);
339                     
340   g_signal_emit_by_name (socket_, "plug_removed", &result);
341   if (!result)
342     gtk_widget_destroy (GTK_WIDGET (socket_));
343
344   if (widget->window)
345     _gtk_plug_send_delete_event (widget);
346
347   g_object_unref (plug);
348
349   if (widget_was_visible && GTK_WIDGET_VISIBLE (socket_))
350     gtk_widget_queue_resize (GTK_WIDGET (socket_));
351
352   g_object_unref (socket_);
353 }
354
355 /**
356  * gtk_plug_construct:
357  * @plug: a #GtkPlug.
358  * @socket_id: the XID of the socket's window.
359  *
360  * Finish the initialization of @plug for a given #GtkSocket identified by
361  * @socket_id. This function will generally only be used by classes deriving from #GtkPlug.
362  **/
363 void
364 gtk_plug_construct (GtkPlug         *plug,
365                     GdkNativeWindow  socket_id)
366 {
367   gtk_plug_construct_for_display (plug, gdk_display_get_default (), socket_id);
368 }
369
370 /**
371  * gtk_plug_construct_for_display:
372  * @plug: a #GtkPlug.
373  * @display: the #GdkDisplay associated with @socket_id's 
374  *           #GtkSocket.
375  * @socket_id: the XID of the socket's window.
376  *
377  * Finish the initialization of @plug for a given #GtkSocket identified by
378  * @socket_id which is currently displayed on @display.
379  * This function will generally only be used by classes deriving from #GtkPlug.
380  *
381  * Since: 2.2
382  **/
383 void
384 gtk_plug_construct_for_display (GtkPlug         *plug,
385                                 GdkDisplay      *display,
386                                 GdkNativeWindow  socket_id)
387 {
388   if (socket_id)
389     {
390       gpointer user_data = NULL;
391
392       plug->socket_window = gdk_window_lookup_for_display (display, socket_id);
393       
394       if (plug->socket_window)
395         gdk_window_get_user_data (plug->socket_window, &user_data);
396       else
397         plug->socket_window = gdk_window_foreign_new_for_display (display, socket_id);
398           
399       if (user_data)
400         {
401           if (GTK_IS_SOCKET (user_data))
402             _gtk_plug_add_to_socket (plug, user_data);
403           else
404             {
405               g_warning (G_STRLOC "Can't create GtkPlug as child of non-GtkSocket");
406               plug->socket_window = NULL;
407             }
408         }
409
410       if (plug->socket_window)
411         g_signal_emit (plug, plug_signals[EMBEDDED], 0);
412     }
413 }
414
415 /**
416  * gtk_plug_new:
417  * @socket_id:  the window ID of the socket, or 0.
418  * 
419  * Creates a new plug widget inside the #GtkSocket identified
420  * by @socket_id. If @socket_id is 0, the plug is left "unplugged" and
421  * can later be plugged into a #GtkSocket by  gtk_socket_add_id().
422  * 
423  * Return value: the new #GtkPlug widget.
424  **/
425 GtkWidget*
426 gtk_plug_new (GdkNativeWindow socket_id)
427 {
428   return gtk_plug_new_for_display (gdk_display_get_default (), socket_id);
429 }
430
431 /**
432  * gtk_plug_new_for_display:
433  * @display : the #GdkDisplay on which @socket_id is displayed
434  * @socket_id: the XID of the socket's window.
435  * 
436  * Create a new plug widget inside the #GtkSocket identified by socket_id.
437  *
438  * Return value: the new #GtkPlug widget.
439  *
440  * Since: 2.2
441  */
442 GtkWidget*
443 gtk_plug_new_for_display (GdkDisplay      *display,
444                           GdkNativeWindow  socket_id)
445 {
446   GtkPlug *plug;
447
448   plug = g_object_new (GTK_TYPE_PLUG, NULL);
449   gtk_plug_construct_for_display (plug, display, socket_id);
450   return GTK_WIDGET (plug);
451 }
452
453 static void
454 gtk_plug_finalize (GObject *object)
455 {
456   GtkPlug *plug = GTK_PLUG (object);
457
458   if (plug->grabbed_keys)
459     {
460       g_hash_table_destroy (plug->grabbed_keys);
461       plug->grabbed_keys = NULL;
462     }
463   
464   G_OBJECT_CLASS (parent_class)->finalize (object);
465 }
466
467 static void
468 gtk_plug_unrealize (GtkWidget *widget)
469 {
470   GtkPlug *plug;
471
472   g_return_if_fail (GTK_IS_PLUG (widget));
473
474   plug = GTK_PLUG (widget);
475
476   if (plug->socket_window != NULL)
477     {
478       gdk_window_set_user_data (plug->socket_window, NULL);
479       g_object_unref (plug->socket_window);
480       plug->socket_window = NULL;
481     }
482
483   if (!plug->same_app)
484     {
485       if (plug->modality_window)
486         _gtk_plug_handle_modality_off (plug);
487
488       gtk_window_group_remove_window (plug->modality_group, GTK_WINDOW (plug));
489       g_object_unref (plug->modality_group);
490     }
491   
492   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
493     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
494 }
495
496 static void
497 gtk_plug_realize (GtkWidget *widget)
498 {
499   GtkWindow *window;
500   GtkPlug *plug;
501   GdkWindowAttr attributes;
502   gint attributes_mask;
503
504   g_return_if_fail (GTK_IS_PLUG (widget));
505
506   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
507   window = GTK_WINDOW (widget);
508   plug = GTK_PLUG (widget);
509
510   attributes.window_type = GDK_WINDOW_CHILD;    /* XXX GDK_WINDOW_PLUG ? */
511   attributes.title = window->title;
512   attributes.wmclass_name = window->wmclass_name;
513   attributes.wmclass_class = window->wmclass_class;
514   attributes.width = widget->allocation.width;
515   attributes.height = widget->allocation.height;
516   attributes.wclass = GDK_INPUT_OUTPUT;
517
518   /* this isn't right - we should match our parent's visual/colormap.
519    * though that will require handling "foreign" colormaps */
520   attributes.visual = gtk_widget_get_visual (widget);
521   attributes.colormap = gtk_widget_get_colormap (widget);
522   attributes.event_mask = gtk_widget_get_events (widget);
523   attributes.event_mask |= (GDK_EXPOSURE_MASK |
524                             GDK_KEY_PRESS_MASK |
525                             GDK_KEY_RELEASE_MASK |
526                             GDK_ENTER_NOTIFY_MASK |
527                             GDK_LEAVE_NOTIFY_MASK |
528                             GDK_STRUCTURE_MASK);
529
530   attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
531   attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
532   attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
533
534   if (GTK_WIDGET_TOPLEVEL (widget))
535     {
536       attributes.window_type = GDK_WINDOW_TOPLEVEL;
537
538       gdk_error_trap_push ();
539       if (plug->socket_window)
540         widget->window = gdk_window_new (plug->socket_window, 
541                                          &attributes, attributes_mask);
542       else /* If it's a passive plug, we use the root window */
543         widget->window = gdk_window_new (gtk_widget_get_root_window (widget),
544                                          &attributes, attributes_mask);
545
546       gdk_display_sync (gtk_widget_get_display (widget));
547       if (gdk_error_trap_pop ()) /* Uh-oh */
548         {
549           gdk_error_trap_push ();
550           gdk_window_destroy (widget->window);
551           gdk_flush ();
552           gdk_error_trap_pop ();
553           widget->window = gdk_window_new (gtk_widget_get_root_window (widget),
554                                            &attributes, attributes_mask);
555         }
556       
557       gdk_window_add_filter (widget->window,
558                              _gtk_plug_windowing_filter_func,
559                              widget);
560
561       plug->modality_group = gtk_window_group_new ();
562       gtk_window_group_add_window (plug->modality_group, window);
563       
564       _gtk_plug_windowing_realize_toplevel (plug);
565     }
566   else
567     widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), 
568                                      &attributes, attributes_mask);      
569   
570   gdk_window_set_user_data (widget->window, window);
571
572   widget->style = gtk_style_attach (widget->style, widget->window);
573   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
574
575   gdk_window_enable_synchronized_configure (widget->window);
576 }
577
578 static void
579 gtk_plug_show (GtkWidget *widget)
580 {
581   if (GTK_WIDGET_TOPLEVEL (widget))
582     GTK_WIDGET_CLASS (parent_class)->show (widget);
583   else
584     GTK_WIDGET_CLASS (bin_class)->show (widget);
585 }
586
587 static void
588 gtk_plug_hide (GtkWidget *widget)
589 {
590   if (GTK_WIDGET_TOPLEVEL (widget))
591     GTK_WIDGET_CLASS (parent_class)->hide (widget);
592   else
593     GTK_WIDGET_CLASS (bin_class)->hide (widget);
594 }
595
596 /* From gdkinternals.h */
597 void gdk_synthesize_window_state (GdkWindow     *window,
598                                   GdkWindowState unset_flags,
599                                   GdkWindowState set_flags);
600
601 static void
602 gtk_plug_map (GtkWidget *widget)
603 {
604   if (GTK_WIDGET_TOPLEVEL (widget))
605     {
606       GtkBin *bin = GTK_BIN (widget);
607       GtkPlug *plug = GTK_PLUG (widget);
608       
609       GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
610
611       if (bin->child &&
612           GTK_WIDGET_VISIBLE (bin->child) &&
613           !GTK_WIDGET_MAPPED (bin->child))
614         gtk_widget_map (bin->child);
615
616       _gtk_plug_windowing_map_toplevel (plug);
617       
618       gdk_synthesize_window_state (widget->window,
619                                    GDK_WINDOW_STATE_WITHDRAWN,
620                                    0);
621     }
622   else
623     GTK_WIDGET_CLASS (bin_class)->map (widget);
624 }
625
626 static void
627 gtk_plug_unmap (GtkWidget *widget)
628 {
629   if (GTK_WIDGET_TOPLEVEL (widget))
630     {
631       GtkPlug *plug = GTK_PLUG (widget);
632
633       GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
634
635       gdk_window_hide (widget->window);
636
637       _gtk_plug_windowing_unmap_toplevel (plug);
638       
639       gdk_synthesize_window_state (widget->window,
640                                    0,
641                                    GDK_WINDOW_STATE_WITHDRAWN);
642     }
643   else
644     GTK_WIDGET_CLASS (bin_class)->unmap (widget);
645 }
646
647 static void
648 gtk_plug_size_allocate (GtkWidget     *widget,
649                         GtkAllocation *allocation)
650 {
651   if (GTK_WIDGET_TOPLEVEL (widget))
652     GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
653   else
654     {
655       GtkBin *bin = GTK_BIN (widget);
656
657       widget->allocation = *allocation;
658
659       if (GTK_WIDGET_REALIZED (widget))
660         gdk_window_move_resize (widget->window,
661                                 allocation->x, allocation->y,
662                                 allocation->width, allocation->height);
663
664       if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
665         {
666           GtkAllocation child_allocation;
667           
668           child_allocation.x = child_allocation.y = GTK_CONTAINER (widget)->border_width;
669           child_allocation.width =
670             MAX (1, (gint)allocation->width - child_allocation.x * 2);
671           child_allocation.height =
672             MAX (1, (gint)allocation->height - child_allocation.y * 2);
673           
674           gtk_widget_size_allocate (bin->child, &child_allocation);
675         }
676       
677     }
678 }
679
680 static gboolean
681 gtk_plug_key_press_event (GtkWidget   *widget,
682                           GdkEventKey *event)
683 {
684   if (GTK_WIDGET_TOPLEVEL (widget))
685     return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
686   else
687     return FALSE;
688 }
689
690 static gboolean
691 gtk_plug_focus_event (GtkWidget      *widget,
692                       GdkEventFocus  *event)
693 {
694   /* We eat focus-in events and focus-out events, since they
695    * can be generated by something like a keyboard grab on
696    * a child of the plug.
697    */
698   return FALSE;
699 }
700
701 static void
702 gtk_plug_set_focus (GtkWindow *window,
703                     GtkWidget *focus)
704 {
705   GtkPlug *plug = GTK_PLUG (window);
706
707   GTK_WINDOW_CLASS (parent_class)->set_focus (window, focus);
708   
709   /* Ask for focus from embedder
710    */
711
712   if (focus && !window->has_toplevel_focus)
713     _gtk_plug_windowing_set_focus (plug);
714 }
715
716 static guint
717 grabbed_key_hash (gconstpointer a)
718 {
719   const GrabbedKey *key = a;
720   guint h;
721   
722   h = key->accelerator_key << 16;
723   h ^= key->accelerator_key >> 16;
724   h ^= key->accelerator_mods;
725
726   return h;
727 }
728
729 static gboolean
730 grabbed_key_equal (gconstpointer a, gconstpointer b)
731 {
732   const GrabbedKey *keya = a;
733   const GrabbedKey *keyb = b;
734
735   return (keya->accelerator_key == keyb->accelerator_key &&
736           keya->accelerator_mods == keyb->accelerator_mods);
737 }
738
739 static void
740 add_grabbed_key (gpointer key, gpointer val, gpointer data)
741 {
742   GrabbedKey *grabbed_key = key;
743   GtkPlug *plug = data;
744
745   if (!plug->grabbed_keys ||
746       !g_hash_table_lookup (plug->grabbed_keys, grabbed_key))
747     {
748       _gtk_plug_windowing_add_grabbed_key (plug,
749                                            grabbed_key->accelerator_key,
750                                            grabbed_key->accelerator_mods);
751     }
752 }
753
754 static void
755 add_grabbed_key_always (gpointer key,
756                         gpointer val,
757                         gpointer data)
758 {
759   GrabbedKey *grabbed_key = key;
760   GtkPlug *plug = data;
761
762   _gtk_plug_windowing_add_grabbed_key (plug,
763                                        grabbed_key->accelerator_key,
764                                        grabbed_key->accelerator_mods);
765 }
766
767 /**
768  * _gtk_plug_add_all_grabbed_keys:
769  *
770  * @plug: a #GtkPlug
771  *
772  * Calls _gtk_plug_windowing_add_grabbed_key() on all the grabbed keys
773  * in the @plug.
774  */
775 void
776 _gtk_plug_add_all_grabbed_keys (GtkPlug *plug)
777 {
778   if (plug->grabbed_keys)
779     g_hash_table_foreach (plug->grabbed_keys, add_grabbed_key_always, plug);
780 }
781
782 static void
783 remove_grabbed_key (gpointer key, gpointer val, gpointer data)
784 {
785   GrabbedKey *grabbed_key = key;
786   GtkPlug *plug = data;
787
788   if (!plug->grabbed_keys ||
789       !g_hash_table_lookup (plug->grabbed_keys, grabbed_key))
790     {
791       _gtk_plug_windowing_remove_grabbed_key (plug, 
792                                               grabbed_key->accelerator_key,
793                                               grabbed_key->accelerator_mods);
794     }
795 }
796
797 static void
798 keys_foreach (GtkWindow      *window,
799               guint           keyval,
800               GdkModifierType modifiers,
801               gboolean        is_mnemonic,
802               gpointer        data)
803 {
804   GHashTable *new_grabbed_keys = data;
805   GrabbedKey *key = g_new (GrabbedKey, 1);
806
807   key->accelerator_key = keyval;
808   key->accelerator_mods = modifiers;
809   
810   g_hash_table_replace (new_grabbed_keys, key, key);
811 }
812
813 static void
814 gtk_plug_keys_changed (GtkWindow *window)
815 {
816   GHashTable *new_grabbed_keys, *old_grabbed_keys;
817   GtkPlug *plug = GTK_PLUG (window);
818
819   new_grabbed_keys = g_hash_table_new_full (grabbed_key_hash, grabbed_key_equal, (GDestroyNotify)g_free, NULL);
820   _gtk_window_keys_foreach (window, keys_foreach, new_grabbed_keys);
821
822   if (plug->socket_window)
823     g_hash_table_foreach (new_grabbed_keys, add_grabbed_key, plug);
824
825   old_grabbed_keys = plug->grabbed_keys;
826   plug->grabbed_keys = new_grabbed_keys;
827
828   if (old_grabbed_keys)
829     {
830       if (plug->socket_window)
831         g_hash_table_foreach (old_grabbed_keys, remove_grabbed_key, plug);
832       g_hash_table_destroy (old_grabbed_keys);
833     }
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     _gtk_plug_windowing_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 /**
890  * _gtk_plug_handle_modality_on:
891  *
892  * @plug: a #GtkPlug
893  *
894  * Called from the GtkPlug backend when the corresponding socket has
895  * told the plug that it modality has toggled on.
896  */
897 void
898 _gtk_plug_handle_modality_on (GtkPlug *plug)
899 {
900   if (!plug->modality_window)
901     {
902       plug->modality_window = gtk_window_new (GTK_WINDOW_POPUP);
903       gtk_window_set_screen (GTK_WINDOW (plug->modality_window),
904                              gtk_widget_get_screen (GTK_WIDGET (plug)));
905       gtk_widget_realize (plug->modality_window);
906       gtk_window_group_add_window (plug->modality_group, GTK_WINDOW (plug->modality_window));
907       gtk_grab_add (plug->modality_window);
908     }
909 }
910
911 /**
912  * _gtk_plug_handle_modality_off:
913  *
914  * @plug: a #GtkPlug
915  *
916  * Called from the GtkPlug backend when the corresponding socket has
917  * told the plug that it modality has toggled off.
918  */
919 void
920 _gtk_plug_handle_modality_off (GtkPlug *plug)
921 {
922   if (plug->modality_window)
923     {
924       gtk_widget_destroy (plug->modality_window);
925       plug->modality_window = NULL;
926     }
927 }
928
929 /**
930  * _gtk_plug_focus_first_last:
931  *
932  * @plug: a #GtkPlug
933  * @direction: a direction
934  *
935  * Called from the GtkPlug backend when the corresponding socket has
936  * told the plug that it has received the focus.
937  */
938 void
939 _gtk_plug_focus_first_last (GtkPlug          *plug,
940                             GtkDirectionType  direction)
941 {
942   GtkWindow *window = GTK_WINDOW (plug);
943   GtkWidget *parent;
944
945   if (window->focus_widget)
946     {
947       parent = window->focus_widget->parent;
948       while (parent)
949         {
950           gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
951           parent = GTK_WIDGET (parent)->parent;
952         }
953       
954       gtk_window_set_focus (GTK_WINDOW (plug), NULL);
955     }
956
957   gtk_widget_child_focus (GTK_WIDGET (plug), direction);
958 }
959
960 #define __GTK_PLUG_C__
961 #include "gtkaliasdef.c"