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