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