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