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