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