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