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