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