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