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