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