]> Pileus Git - ~andy/gtk/blob - gtk/gtksocket.c
Deprecate flag macros for toplevel, state, no window and composite child
[~andy/gtk] / gtk / gtksocket.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 #include <string.h>
30
31 #include "gdk/gdkkeysyms.h"
32 #include "gtkmain.h"
33 #include "gtkmarshalers.h"
34 #include "gtkwindow.h"
35 #include "gtkplug.h"
36 #include "gtkprivate.h"
37 #include "gtksocket.h"
38 #include "gtksocketprivate.h"
39 #include "gtkdnd.h"
40 #include "gtkextendedlayout.h"
41 #include "gtkintl.h"
42
43 #include "gtkalias.h"
44
45 /* Forward declararations */
46
47 static void     gtk_socket_finalize             (GObject          *object);
48 static void     gtk_socket_notify               (GObject          *object,
49                                                  GParamSpec       *pspec);
50 static void     gtk_socket_realize              (GtkWidget        *widget);
51 static void     gtk_socket_unrealize            (GtkWidget        *widget);
52 static void     gtk_socket_size_request         (GtkWidget        *widget,
53                                                  GtkRequisition   *requisition);
54 static void     gtk_socket_size_allocate        (GtkWidget        *widget,
55                                                  GtkAllocation    *allocation);
56 static void     gtk_socket_hierarchy_changed    (GtkWidget        *widget,
57                                                  GtkWidget        *old_toplevel);
58 static void     gtk_socket_grab_notify          (GtkWidget        *widget,
59                                                  gboolean          was_grabbed);
60 static gboolean gtk_socket_key_event            (GtkWidget        *widget,
61                                                  GdkEventKey      *event);
62 static gboolean gtk_socket_focus                (GtkWidget        *widget,
63                                                  GtkDirectionType  direction);
64 static void     gtk_socket_remove               (GtkContainer     *container,
65                                                  GtkWidget        *widget);
66 static void     gtk_socket_forall               (GtkContainer     *container,
67                                                  gboolean          include_internals,
68                                                  GtkCallback       callback,
69                                                  gpointer          callback_data);
70
71 static void gtk_socket_extended_layout_interface_init (GtkExtendedLayoutIface *iface);
72
73 /* Local data */
74
75 typedef struct
76 {
77   guint                  accel_key;
78   GdkModifierType        accel_mods;
79 } GrabbedKey;
80
81 enum {
82   PLUG_ADDED,
83   PLUG_REMOVED,
84   LAST_SIGNAL
85 }; 
86
87 static guint socket_signals[LAST_SIGNAL] = { 0 };
88
89 /*
90  * _gtk_socket_get_private:
91  *
92  * @socket: a #GtkSocket
93  *
94  * Returns the private data associated with a GtkSocket, creating it
95  * first if necessary.
96  */
97 GtkSocketPrivate *
98 _gtk_socket_get_private (GtkSocket *socket)
99 {
100   return G_TYPE_INSTANCE_GET_PRIVATE (socket, GTK_TYPE_SOCKET, GtkSocketPrivate);
101 }
102
103 G_DEFINE_TYPE_WITH_CODE (GtkSocket, gtk_socket, GTK_TYPE_CONTAINER,
104                          G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
105                                                 gtk_socket_extended_layout_interface_init))
106
107
108 static void
109 gtk_socket_finalize (GObject *object)
110 {
111   GtkSocket *socket = GTK_SOCKET (object);
112   
113   g_object_unref (socket->accel_group);
114   socket->accel_group = NULL;
115
116   G_OBJECT_CLASS (gtk_socket_parent_class)->finalize (object);
117 }
118
119 static void
120 gtk_socket_class_init (GtkSocketClass *class)
121 {
122   GtkWidgetClass *widget_class;
123   GtkContainerClass *container_class;
124   GObjectClass *gobject_class;
125
126   gobject_class = (GObjectClass *) class;
127   widget_class = (GtkWidgetClass*) class;
128   container_class = (GtkContainerClass*) class;
129
130   gobject_class->finalize = gtk_socket_finalize;
131   gobject_class->notify = gtk_socket_notify;
132
133   widget_class->realize = gtk_socket_realize;
134   widget_class->unrealize = gtk_socket_unrealize;
135   widget_class->size_request = gtk_socket_size_request;
136   widget_class->size_allocate = gtk_socket_size_allocate;
137   widget_class->hierarchy_changed = gtk_socket_hierarchy_changed;
138   widget_class->grab_notify = gtk_socket_grab_notify;
139   widget_class->key_press_event = gtk_socket_key_event;
140   widget_class->key_release_event = gtk_socket_key_event;
141   widget_class->focus = gtk_socket_focus;
142
143   /* We don't want to show_all/hide_all the in-process
144    * plug, if any.
145    */
146   widget_class->show_all = gtk_widget_show;
147   widget_class->hide_all = gtk_widget_hide;
148   
149   container_class->remove = gtk_socket_remove;
150   container_class->forall = gtk_socket_forall;
151
152   /**
153    * GtkSocket::plug-added:
154    * @socket_: the object which received the signal
155    *
156    * This signal is emitted when a client is successfully
157    * added to the socket. 
158    */
159   socket_signals[PLUG_ADDED] =
160     g_signal_new (I_("plug-added"),
161                   G_OBJECT_CLASS_TYPE (class),
162                   G_SIGNAL_RUN_LAST,
163                   G_STRUCT_OFFSET (GtkSocketClass, plug_added),
164                   NULL, NULL,
165                   _gtk_marshal_VOID__VOID,
166                   G_TYPE_NONE, 0);
167
168   /**
169    * GtkSocket::plug-removed:
170    * @socket_: the object which received the signal
171    *
172    * This signal is emitted when a client is removed from the socket. 
173    * The default action is to destroy the #GtkSocket widget, so if you 
174    * want to reuse it you must add a signal handler that returns %TRUE. 
175    *
176    * Return value: %TRUE to stop other handlers from being invoked.
177    */
178   socket_signals[PLUG_REMOVED] =
179     g_signal_new (I_("plug-removed"),
180                   G_OBJECT_CLASS_TYPE (class),
181                   G_SIGNAL_RUN_LAST,
182                   G_STRUCT_OFFSET (GtkSocketClass, plug_removed),
183                   _gtk_boolean_handled_accumulator, NULL,
184                   _gtk_marshal_BOOLEAN__VOID,
185                   G_TYPE_BOOLEAN, 0);
186
187   g_type_class_add_private (gobject_class, sizeof (GtkSocketPrivate));
188 }
189
190 static void
191 gtk_socket_init (GtkSocket *socket)
192 {
193   GtkSocketPrivate *priv;
194
195   socket->request_width = 0;
196   socket->request_height = 0;
197   socket->current_width = 0;
198   socket->current_height = 0;
199   
200   socket->plug_window = NULL;
201   socket->plug_widget = NULL;
202   socket->focus_in = FALSE;
203   socket->have_size = FALSE;
204   socket->need_map = FALSE;
205   socket->active = FALSE;
206
207   socket->accel_group = gtk_accel_group_new ();
208   g_object_set_data (G_OBJECT (socket->accel_group), I_("gtk-socket"), socket);
209
210   priv = _gtk_socket_get_private (socket);
211   priv->have_natural_size = FALSE;
212 }
213
214 /**
215  * gtk_socket_new:
216  * 
217  * Create a new empty #GtkSocket.
218  * 
219  * Return value:  the new #GtkSocket.
220  **/
221 GtkWidget*
222 gtk_socket_new (void)
223 {
224   GtkSocket *socket;
225
226   socket = g_object_new (GTK_TYPE_SOCKET, NULL);
227
228   return GTK_WIDGET (socket);
229 }
230
231 /**
232  * gtk_socket_steal:
233  * @socket_: a #GtkSocket
234  * @wid: the window ID of an existing toplevel window.
235  * 
236  * Reparents a pre-existing toplevel window into a #GtkSocket. This is
237  * meant to embed clients that do not know about embedding into a
238  * #GtkSocket, however doing so is inherently unreliable, and using
239  * this function is not recommended.
240  *
241  * The #GtkSocket must have already be added into a toplevel window
242  *  before you can make this call.
243  **/
244 void           
245 gtk_socket_steal (GtkSocket      *socket,
246                   GdkNativeWindow wid)
247 {
248   g_return_if_fail (GTK_IS_SOCKET (socket));
249   g_return_if_fail (GTK_WIDGET_ANCHORED (socket));
250
251   if (!GTK_WIDGET_REALIZED (socket))
252     gtk_widget_realize (GTK_WIDGET (socket));
253
254   _gtk_socket_add_window (socket, wid, TRUE);
255 }
256
257 /**
258  * gtk_socket_add_id:
259  * @socket_: a #GtkSocket
260  * @window_id: the window ID of a client participating in the XEMBED protocol.
261  *
262  * Adds an XEMBED client, such as a #GtkPlug, to the #GtkSocket.  The
263  * client may be in the same process or in a different process. 
264  * 
265  * To embed a #GtkPlug in a #GtkSocket, you can either create the
266  * #GtkPlug with <literal>gtk_plug_new (0)</literal>, call 
267  * gtk_plug_get_id() to get the window ID of the plug, and then pass that to the
268  * gtk_socket_add_id(), or you can call gtk_socket_get_id() to get the
269  * window ID for the socket, and call gtk_plug_new() passing in that
270  * ID.
271  *
272  * The #GtkSocket must have already be added into a toplevel window
273  *  before you can make this call.
274  **/
275 void           
276 gtk_socket_add_id (GtkSocket      *socket,
277                    GdkNativeWindow window_id)
278 {
279   g_return_if_fail (GTK_IS_SOCKET (socket));
280   g_return_if_fail (GTK_WIDGET_ANCHORED (socket));
281
282   if (!GTK_WIDGET_REALIZED (socket))
283     gtk_widget_realize (GTK_WIDGET (socket));
284
285   _gtk_socket_add_window (socket, window_id, TRUE);
286 }
287
288 /**
289  * gtk_socket_get_id:
290  * @socket_: a #GtkSocket.
291  * 
292  * Gets the window ID of a #GtkSocket widget, which can then
293  * be used to create a client embedded inside the socket, for
294  * instance with gtk_plug_new(). 
295  *
296  * The #GtkSocket must have already be added into a toplevel window 
297  * before you can make this call.
298  * 
299  * Return value: the window ID for the socket
300  **/
301 GdkNativeWindow
302 gtk_socket_get_id (GtkSocket *socket)
303 {
304   g_return_val_if_fail (GTK_IS_SOCKET (socket), 0);
305   g_return_val_if_fail (GTK_WIDGET_ANCHORED (socket), 0);
306
307   if (!GTK_WIDGET_REALIZED (socket))
308     gtk_widget_realize (GTK_WIDGET (socket));
309
310   return _gtk_socket_windowing_get_id (socket);
311 }
312
313 /**
314  * gtk_socket_get_plug_window:
315  * @socket_: a #GtkSocket.
316  *
317  * Retrieves the window of the plug. Use this to check if the plug has
318  * been created inside of the socket.
319  *
320  * Return value: the window of the plug if available, or %NULL
321  *
322  * Since:  2.14
323  **/
324 GdkWindow*
325 gtk_socket_get_plug_window (GtkSocket *socket)
326 {
327   g_return_val_if_fail (GTK_IS_SOCKET (socket), NULL);
328
329   return socket->plug_window;
330 }
331
332 static void
333 gtk_socket_realize (GtkWidget *widget)
334 {
335   GtkSocket *socket = GTK_SOCKET (widget);
336   GdkWindowAttr attributes;
337   gint attributes_mask;
338
339   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
340
341   attributes.window_type = GDK_WINDOW_CHILD;
342   attributes.x = widget->allocation.x;
343   attributes.y = widget->allocation.y;
344   attributes.width = widget->allocation.width;
345   attributes.height = widget->allocation.height;
346   attributes.wclass = GDK_INPUT_OUTPUT;
347   attributes.visual = gtk_widget_get_visual (widget);
348   attributes.colormap = gtk_widget_get_colormap (widget);
349   attributes.event_mask = GDK_FOCUS_CHANGE_MASK;
350
351   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
352
353   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), 
354                                    &attributes, attributes_mask);
355   gdk_window_set_user_data (widget->window, socket);
356
357   widget->style = gtk_style_attach (widget->style, widget->window);
358   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
359
360   _gtk_socket_windowing_realize_window (socket);
361
362   gdk_window_add_filter (widget->window,
363                          _gtk_socket_windowing_filter_func,
364                          widget);
365
366   /* We sync here so that we make sure that if the XID for
367    * our window is passed to another application, SubstructureRedirectMask
368    * will be set by the time the other app creates its window.
369    */
370   gdk_display_sync (gtk_widget_get_display (widget));
371 }
372
373 /**
374  * _gtk_socket_end_embedding:
375  *
376  * @socket: a #GtkSocket
377  *
378  * Called to end the embedding of a plug in the socket.
379  */
380 void
381 _gtk_socket_end_embedding (GtkSocket *socket)
382 {
383   GtkSocketPrivate *private = _gtk_socket_get_private (socket);
384   GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
385   
386   if (GTK_IS_WINDOW (toplevel))
387     _gtk_socket_windowing_end_embedding_toplevel (socket);
388
389   g_object_unref (socket->plug_window);
390   socket->plug_window = NULL;
391   socket->current_width = 0;
392   socket->current_height = 0;
393   private->resize_count = 0;
394
395   gtk_accel_group_disconnect (socket->accel_group, NULL);
396 }
397
398 static void
399 gtk_socket_unrealize (GtkWidget *widget)
400 {
401   GtkSocket *socket = GTK_SOCKET (widget);
402
403   GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED);
404
405   if (socket->plug_widget)
406     {
407       _gtk_plug_remove_from_socket (GTK_PLUG (socket->plug_widget), socket);
408     }
409   else if (socket->plug_window)
410     {
411       _gtk_socket_end_embedding (socket);
412     }
413
414   GTK_WIDGET_CLASS (gtk_socket_parent_class)->unrealize (widget);
415 }
416
417 static void
418 gtk_socket_size_request (GtkWidget      *widget,
419                          GtkRequisition *requisition)
420 {
421   GtkSocket *socket = GTK_SOCKET (widget);
422
423   if (socket->plug_widget)
424     {
425       gtk_widget_size_request (socket->plug_widget, requisition);
426     }
427   else
428     {
429       if (socket->is_mapped && !socket->have_size && socket->plug_window)
430         _gtk_socket_windowing_size_request (socket);
431
432       if (socket->is_mapped && socket->have_size)
433         {
434           requisition->width = MAX (socket->request_width, 1);
435           requisition->height = MAX (socket->request_height, 1);
436         }
437       else
438         {
439           requisition->width = 1;
440           requisition->height = 1;
441         }
442     }
443 }
444
445 static void
446 gtk_socket_size_allocate (GtkWidget     *widget,
447                           GtkAllocation *allocation)
448 {
449   GtkSocket *socket = GTK_SOCKET (widget);
450
451   widget->allocation = *allocation;
452   if (GTK_WIDGET_REALIZED (widget))
453     {
454       gdk_window_move_resize (widget->window,
455                               allocation->x, allocation->y,
456                               allocation->width, allocation->height);
457
458       if (socket->plug_widget)
459         {
460           GtkAllocation child_allocation;
461
462           child_allocation.x = 0;
463           child_allocation.y = 0;
464           child_allocation.width = allocation->width;
465           child_allocation.height = allocation->height;
466
467           gtk_widget_size_allocate (socket->plug_widget, &child_allocation);
468         }
469       else if (socket->plug_window)
470         {
471           GtkSocketPrivate *private = _gtk_socket_get_private (socket);
472           
473           gdk_error_trap_push ();
474           
475           if (allocation->width != socket->current_width ||
476               allocation->height != socket->current_height)
477             {
478               gdk_window_move_resize (socket->plug_window,
479                                       0, 0,
480                                       allocation->width, allocation->height);
481               if (private->resize_count)
482                 private->resize_count--;
483               
484               GTK_NOTE (PLUGSOCKET,
485                         g_message ("GtkSocket - allocated: %d %d",
486                                    allocation->width, allocation->height));
487               socket->current_width = allocation->width;
488               socket->current_height = allocation->height;
489             }
490
491           if (socket->need_map)
492             {
493               gdk_window_show (socket->plug_window);
494               socket->need_map = FALSE;
495             }
496
497           while (private->resize_count)
498             {
499               _gtk_socket_windowing_send_configure_event (socket);
500               private->resize_count--;
501               GTK_NOTE (PLUGSOCKET,
502                         g_message ("GtkSocket - sending synthetic configure: %d %d",
503                                    allocation->width, allocation->height));
504             }
505           
506           gdk_display_sync (gtk_widget_get_display (widget));
507           gdk_error_trap_pop ();
508         }
509     }
510 }
511
512 static gboolean
513 activate_key (GtkAccelGroup  *accel_group,
514               GObject        *acceleratable,
515               guint           accel_key,
516               GdkModifierType accel_mods,
517               GrabbedKey     *grabbed_key)
518 {
519   GdkEvent *gdk_event = gtk_get_current_event ();
520   
521   GtkSocket *socket = g_object_get_data (G_OBJECT (accel_group), "gtk-socket");
522   gboolean retval = FALSE;
523
524   if (gdk_event && gdk_event->type == GDK_KEY_PRESS && socket->plug_window)
525     {
526       _gtk_socket_windowing_send_key_event (socket, gdk_event, TRUE);
527       retval = TRUE;
528     }
529
530   if (gdk_event)
531     gdk_event_free (gdk_event);
532
533   return retval;
534 }
535
536 static gboolean
537 find_accel_key (GtkAccelKey *key,
538                 GClosure    *closure,
539                 gpointer     data)
540 {
541   GrabbedKey *grabbed_key = data;
542   
543   return (key->accel_key == grabbed_key->accel_key &&
544           key->accel_mods == grabbed_key->accel_mods);
545 }
546
547 /**
548  * _gtk_socket_add_grabbed_key:
549  *
550  * @socket: a #GtkSocket
551  * @keyval: a key
552  * @modifiers: modifiers for the key
553  *
554  * Called from the GtkSocket platform-specific backend when the
555  * corresponding plug has told the socket to grab a key.
556  */
557 void
558 _gtk_socket_add_grabbed_key (GtkSocket       *socket,
559                              guint            keyval,
560                              GdkModifierType  modifiers)
561 {
562   GClosure *closure;
563   GrabbedKey *grabbed_key;
564
565   grabbed_key = g_new (GrabbedKey, 1);
566   
567   grabbed_key->accel_key = keyval;
568   grabbed_key->accel_mods = modifiers;
569
570   if (gtk_accel_group_find (socket->accel_group,
571                             find_accel_key,
572                             &grabbed_key))
573     {
574       g_warning ("GtkSocket: request to add already present grabbed key %u,%#x\n",
575                  keyval, modifiers);
576       g_free (grabbed_key);
577       return;
578     }
579
580   closure = g_cclosure_new (G_CALLBACK (activate_key), grabbed_key, (GClosureNotify)g_free);
581
582   gtk_accel_group_connect (socket->accel_group, keyval, modifiers, GTK_ACCEL_LOCKED,
583                            closure);
584 }
585
586 /**
587  * _gtk_socket_remove_grabbed_key:
588  *
589  * @socket: a #GtkSocket
590  * @keyval: a key
591  * @modifiers: modifiers for the key
592  *
593  * Called from the GtkSocket backend when the corresponding plug has
594  * told the socket to remove a key grab.
595  */
596 void
597 _gtk_socket_remove_grabbed_key (GtkSocket      *socket,
598                                 guint           keyval,
599                                 GdkModifierType modifiers)
600 {
601   if (!gtk_accel_group_disconnect_key (socket->accel_group, keyval, modifiers))
602     g_warning ("GtkSocket: request to remove non-present grabbed key %u,%#x\n",
603                keyval, modifiers);
604 }
605
606 static void
607 socket_update_focus_in (GtkSocket *socket)
608 {
609   gboolean focus_in = FALSE;
610
611   if (socket->plug_window)
612     {
613       GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
614
615       if (gtk_widget_is_toplevel (toplevel) &&
616           GTK_WINDOW (toplevel)->has_toplevel_focus &&
617           gtk_widget_is_focus (GTK_WIDGET (socket)))
618         focus_in = TRUE;
619     }
620
621   if (focus_in != socket->focus_in)
622     {
623       socket->focus_in = focus_in;
624
625       _gtk_socket_windowing_focus_change (socket, focus_in);
626     }
627 }
628
629 static void
630 socket_update_active (GtkSocket *socket)
631 {
632   gboolean active = FALSE;
633
634   if (socket->plug_window)
635     {
636       GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
637
638       if (gtk_widget_is_toplevel (toplevel) &&
639           GTK_WINDOW (toplevel)->is_active)
640         active = TRUE;
641     }
642
643   if (active != socket->active)
644     {
645       socket->active = active;
646
647       _gtk_socket_windowing_update_active (socket, active);
648     }
649 }
650
651 static void
652 gtk_socket_hierarchy_changed (GtkWidget *widget,
653                               GtkWidget *old_toplevel)
654 {
655   GtkSocket *socket = GTK_SOCKET (widget);
656   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
657
658   if (toplevel && !GTK_IS_WINDOW (toplevel))
659     toplevel = NULL;
660
661   if (toplevel != socket->toplevel)
662     {
663       if (socket->toplevel)
664         {
665           gtk_window_remove_accel_group (GTK_WINDOW (socket->toplevel), socket->accel_group);
666           g_signal_handlers_disconnect_by_func (socket->toplevel,
667                                                 socket_update_focus_in,
668                                                 socket);
669           g_signal_handlers_disconnect_by_func (socket->toplevel,
670                                                 socket_update_active,
671                                                 socket);
672         }
673
674       socket->toplevel = toplevel;
675
676       if (toplevel)
677         {
678           gtk_window_add_accel_group (GTK_WINDOW (socket->toplevel), socket->accel_group);
679           g_signal_connect_swapped (socket->toplevel, "notify::has-toplevel-focus",
680                                     G_CALLBACK (socket_update_focus_in), socket);
681           g_signal_connect_swapped (socket->toplevel, "notify::is-active",
682                                     G_CALLBACK (socket_update_active), socket);
683         }
684
685       socket_update_focus_in (socket);
686       socket_update_active (socket);
687     }
688 }
689
690 static void
691 gtk_socket_grab_notify (GtkWidget *widget,
692                         gboolean   was_grabbed)
693 {
694   GtkSocket *socket = GTK_SOCKET (widget);
695
696   if (!socket->same_app)
697     _gtk_socket_windowing_update_modality (socket, !was_grabbed);
698 }
699
700 static gboolean
701 gtk_socket_key_event (GtkWidget   *widget,
702                       GdkEventKey *event)
703 {
704   GtkSocket *socket = GTK_SOCKET (widget);
705   
706   if (GTK_WIDGET_HAS_FOCUS (socket) && socket->plug_window && !socket->plug_widget)
707     {
708       _gtk_socket_windowing_send_key_event (socket, (GdkEvent *) event, FALSE);
709
710       return TRUE;
711     }
712   else
713     return FALSE;
714 }
715
716 static void
717 gtk_socket_notify (GObject    *object,
718                    GParamSpec *pspec)
719 {
720   if (!strcmp (pspec->name, "is-focus"))
721     return;
722   socket_update_focus_in (GTK_SOCKET (object));
723 }
724
725 /**
726  * _gtk_socket_claim_focus:
727  *
728  * @socket: a #GtkSocket
729  * @send_event: huh?
730  *
731  * Claims focus for the socket. XXX send_event?
732  */
733 void
734 _gtk_socket_claim_focus (GtkSocket *socket,
735                          gboolean   send_event)
736 {
737   if (!send_event)
738     socket->focus_in = TRUE;    /* Otherwise, our notify handler will send FOCUS_IN  */
739       
740   /* Oh, the trickery... */
741   
742   GTK_WIDGET_SET_FLAGS (socket, GTK_CAN_FOCUS);
743   gtk_widget_grab_focus (GTK_WIDGET (socket));
744   GTK_WIDGET_UNSET_FLAGS (socket, GTK_CAN_FOCUS);
745 }
746
747 static gboolean
748 gtk_socket_focus (GtkWidget       *widget,
749                   GtkDirectionType direction)
750 {
751   GtkSocket *socket = GTK_SOCKET (widget);
752
753   if (socket->plug_widget)
754     return gtk_widget_child_focus (socket->plug_widget, direction);
755
756   if (!gtk_widget_is_focus (widget))
757     {
758       _gtk_socket_windowing_focus (socket, direction);
759       _gtk_socket_claim_focus (socket, FALSE);
760  
761       return TRUE;
762     }
763   else
764     return FALSE;
765 }
766
767 static void
768 gtk_socket_remove (GtkContainer *container,
769                    GtkWidget    *child)
770 {
771   GtkSocket *socket = GTK_SOCKET (container);
772
773   g_return_if_fail (child == socket->plug_widget);
774
775   _gtk_plug_remove_from_socket (GTK_PLUG (socket->plug_widget), socket);
776 }
777
778 static void
779 gtk_socket_forall (GtkContainer *container,
780                    gboolean      include_internals,
781                    GtkCallback   callback,
782                    gpointer      callback_data)
783 {
784   GtkSocket *socket = GTK_SOCKET (container);
785
786   if (socket->plug_widget)
787     (* callback) (socket->plug_widget, callback_data);
788 }
789
790 /**
791  * _gtk_socket_add_window:
792  *
793  * @socket: a #GtkSocket
794  * @xid: the native identifier for a window
795  * @need_reparent: whether the socket's plug's window needs to be
796  *                 reparented to the socket
797  *
798  * Adds a window to a GtkSocket.
799  */
800 void
801 _gtk_socket_add_window (GtkSocket       *socket,
802                         GdkNativeWindow  xid,
803                         gboolean         need_reparent)
804 {
805   GtkWidget *widget = GTK_WIDGET (socket);
806   GdkDisplay *display = gtk_widget_get_display (widget);
807   gpointer user_data = NULL;
808   
809   socket->plug_window = gdk_window_lookup_for_display (display, xid);
810
811   if (socket->plug_window)
812     {
813       g_object_ref (socket->plug_window);
814       gdk_window_get_user_data (socket->plug_window, &user_data);
815     }
816
817   if (user_data)                /* A widget's window in this process */
818     {
819       GtkWidget *child_widget = user_data;
820
821       if (!GTK_IS_PLUG (child_widget))
822         {
823           g_warning (G_STRLOC ": Can't add non-GtkPlug to GtkSocket");
824           socket->plug_window = NULL;
825           gdk_error_trap_pop ();
826           
827           return;
828         }
829
830       _gtk_plug_add_to_socket (GTK_PLUG (child_widget), socket);
831     }
832   else                          /* A foreign window */
833     {
834       GtkWidget *toplevel;
835       GdkDragProtocol protocol;
836
837       gdk_error_trap_push ();
838
839       if (!socket->plug_window)
840         {  
841           socket->plug_window = gdk_window_foreign_new_for_display (display, xid);
842           if (!socket->plug_window) /* was deleted before we could get it */
843             {
844               gdk_error_trap_pop ();
845               return;
846             }
847         }
848         
849       _gtk_socket_windowing_select_plug_window_input (socket);
850
851       if (gdk_error_trap_pop ())
852         {
853           g_object_unref (socket->plug_window);
854           socket->plug_window = NULL;
855           return;
856         }
857       
858       /* OK, we now will reliably get destroy notification on socket->plug_window */
859
860       gdk_error_trap_push ();
861
862       if (need_reparent)
863         {
864           gdk_window_hide (socket->plug_window); /* Shouldn't actually be necessary for XEMBED, but just in case */
865           gdk_window_reparent (socket->plug_window, widget->window, 0, 0);
866         }
867
868       socket->have_size = FALSE;
869
870       _gtk_socket_windowing_embed_get_info (socket);
871
872       socket->need_map = socket->is_mapped;
873
874       if (gdk_drag_get_protocol_for_display (display, xid, &protocol))
875         gtk_drag_dest_set_proxy (GTK_WIDGET (socket), socket->plug_window, 
876                                  protocol, TRUE);
877
878       gdk_display_sync (display);
879       gdk_error_trap_pop ();
880
881       gdk_window_add_filter (socket->plug_window,
882                              _gtk_socket_windowing_filter_func,
883                              socket);
884
885       /* Add a pointer to the socket on our toplevel window */
886
887       toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
888       if (GTK_IS_WINDOW (toplevel))
889         gtk_window_add_embedded_xid (GTK_WINDOW (toplevel), xid);
890
891       _gtk_socket_windowing_embed_notify (socket);
892
893       socket_update_active (socket);
894       socket_update_focus_in (socket);
895
896       gtk_widget_queue_resize (GTK_WIDGET (socket));
897     }
898
899   if (socket->plug_window)
900     g_signal_emit (socket, socket_signals[PLUG_ADDED], 0);
901 }
902
903 /**
904  * _gtk_socket_handle_map_request:
905  *
906  * @socket: a #GtkSocket
907  *
908  * Called from the GtkSocket backend when the plug has been mapped.
909  */
910 void
911 _gtk_socket_handle_map_request (GtkSocket *socket)
912 {
913   if (!socket->is_mapped)
914     {
915       socket->is_mapped = TRUE;
916       socket->need_map = TRUE;
917
918       gtk_widget_queue_resize (GTK_WIDGET (socket));
919     }
920 }
921
922 /**
923  * _gtk_socket_unmap_notify:
924  *
925  * @socket: a #GtkSocket
926  *
927  * Called from the GtkSocket backend when the plug has been unmapped ???
928  */
929 void
930 _gtk_socket_unmap_notify (GtkSocket *socket)
931 {
932   if (socket->is_mapped)
933     {
934       socket->is_mapped = FALSE;
935       gtk_widget_queue_resize (GTK_WIDGET (socket));
936     }
937 }
938
939 /**
940  * _gtk_socket_advance_toplevel_focus:
941  *
942  * @socket: a #GtkSocket
943  * @direction: a direction
944  *
945  * Called from the GtkSocket backend when the corresponding plug
946  * has told the socket to move the focus.
947  */
948 void
949 _gtk_socket_advance_toplevel_focus (GtkSocket        *socket,
950                                     GtkDirectionType  direction)
951 {
952   GtkBin *bin;
953   GtkWindow *window;
954   GtkContainer *container;
955   GtkWidget *toplevel;
956   GtkWidget *old_focus_child;
957   GtkWidget *parent;
958
959   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
960   if (!toplevel)
961     return;
962
963   if (!gtk_widget_is_toplevel (toplevel) || GTK_IS_PLUG (toplevel))
964     {
965       gtk_widget_child_focus (toplevel,direction);
966       return;
967     }
968
969   container = GTK_CONTAINER (toplevel);
970   window = GTK_WINDOW (toplevel);
971   bin = GTK_BIN (toplevel);
972
973   /* This is a copy of gtk_window_focus(), modified so that we
974    * can detect wrap-around.
975    */
976   old_focus_child = container->focus_child;
977   
978   if (old_focus_child)
979     {
980       if (gtk_widget_child_focus (old_focus_child, direction))
981         return;
982
983       /* We are allowed exactly one wrap-around per sequence of focus
984        * events
985        */
986       if (_gtk_socket_windowing_embed_get_focus_wrapped ())
987         return;
988       else
989         _gtk_socket_windowing_embed_set_focus_wrapped ();
990     }
991
992   if (window->focus_widget)
993     {
994       /* Wrapped off the end, clear the focus setting for the toplevel */
995       parent = window->focus_widget->parent;
996       while (parent)
997         {
998           gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
999           parent = GTK_WIDGET (parent)->parent;
1000         }
1001       
1002       gtk_window_set_focus (GTK_WINDOW (container), NULL);
1003     }
1004
1005   /* Now try to focus the first widget in the window */
1006   if (bin->child)
1007     {
1008       if (gtk_widget_child_focus (bin->child, direction))
1009         return;
1010     }
1011 }
1012
1013 static void
1014 gtk_socket_extended_layout_get_desired_size (GtkExtendedLayout *layout,
1015                                              GtkRequisition    *minimal_size,
1016                                              GtkRequisition    *desired_size)
1017 {
1018   GtkSocket *socket = GTK_SOCKET (layout);
1019   GtkSocketPrivate *priv;
1020
1021   if (socket->plug_widget)
1022     {
1023       gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (socket->plug_widget),
1024                                                                  minimal_size,
1025                                                                  desired_size); 
1026     }
1027   else
1028     {
1029       priv = _gtk_socket_get_private (socket);
1030
1031       if (socket->is_mapped && !priv->have_natural_size && socket->plug_window)
1032         {
1033            _gtk_socket_windowing_size_request (socket);
1034            _gtk_socket_windowing_get_natural_size (socket);
1035         }
1036
1037       if (socket->is_mapped && priv->have_natural_size)
1038         {
1039           if (minimal_size)
1040             {
1041               minimal_size->width = MAX (socket->request_width, 1);
1042               minimal_size->height = MAX (socket->request_height, 1);
1043             }
1044           if (desired_size)
1045             {
1046               desired_size->width = MAX (priv->natural_width, 1);
1047               desired_size->height = MAX (priv->natural_height, 1);
1048             }
1049         }
1050       else
1051         {
1052           if (minimal_size)
1053             {
1054               minimal_size->width = 1;
1055               minimal_size->height = 1;
1056             }
1057           if (desired_size)
1058             {
1059               desired_size->width = 1;
1060               desired_size->height = 1;
1061             }
1062         }
1063     }
1064 }
1065
1066 static void
1067 gtk_socket_extended_layout_interface_init (GtkExtendedLayoutIface *iface)
1068 {
1069   iface->get_desired_size = gtk_socket_extended_layout_get_desired_size;
1070 }
1071
1072
1073 #define __GTK_SOCKET_C__
1074 #include "gtkaliasdef.c"