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