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