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