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