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