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