1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
19 /* By Owen Taylor <otaylor@gtk.org> 98/4/4 */
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/.
28 #include "gdk/gdkkeysyms.h"
30 #include "gtkmarshal.h"
31 #include "gtkwindow.h"
33 #include "gtkprivate.h"
34 #include "gtksignal.h"
35 #include "gtksocket.h"
42 /* Forward declararations */
44 static void gtk_socket_class_init (GtkSocketClass *klass);
45 static void gtk_socket_init (GtkSocket *socket);
46 static void gtk_socket_realize (GtkWidget *widget);
47 static void gtk_socket_unrealize (GtkWidget *widget);
48 static void gtk_socket_size_request (GtkWidget *widget,
49 GtkRequisition *requisition);
50 static void gtk_socket_size_allocate (GtkWidget *widget,
51 GtkAllocation *allocation);
52 static void gtk_socket_hierarchy_changed (GtkWidget *widget,
53 GtkWidget *old_toplevel);
54 static void gtk_socket_grab_notify (GtkWidget *widget,
55 gboolean was_grabbed);
56 static gboolean gtk_socket_key_press_event (GtkWidget *widget,
58 static gboolean gtk_socket_focus_in_event (GtkWidget *widget,
59 GdkEventFocus *event);
60 static void gtk_socket_claim_focus (GtkSocket *socket);
61 static gboolean gtk_socket_focus_out_event (GtkWidget *widget,
62 GdkEventFocus *event);
63 static void gtk_socket_send_configure_event (GtkSocket *socket);
64 static gboolean gtk_socket_focus (GtkWidget *widget,
65 GtkDirectionType direction);
66 static void gtk_socket_remove (GtkContainer *container,
68 static void gtk_socket_forall (GtkContainer *container,
69 gboolean include_internals,
71 gpointer callback_data);
74 static void gtk_socket_add_window (GtkSocket *socket,
76 gboolean need_reparent);
77 static GdkFilterReturn gtk_socket_filter_func (GdkXEvent *gdk_xevent,
81 static void send_xembed_message (GtkSocket *socket,
87 static gboolean xembed_get_info (GdkWindow *gdk_window,
88 unsigned long *version,
89 unsigned long *flags);
92 #define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
102 static guint socket_signals[LAST_SIGNAL] = { 0 };
104 static GtkWidgetClass *parent_class = NULL;
107 gtk_socket_get_type (void)
109 static GtkType socket_type = 0;
113 static const GTypeInfo socket_info =
115 sizeof (GtkSocketClass),
116 NULL, /* base_init */
117 NULL, /* base_finalize */
118 (GClassInitFunc) gtk_socket_class_init,
119 NULL, /* class_finalize */
120 NULL, /* class_data */
122 16, /* n_preallocs */
123 (GInstanceInitFunc) gtk_socket_init,
126 socket_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkSocket", &socket_info, 0);
133 gtk_socket_class_init (GtkSocketClass *class)
135 GtkWidgetClass *widget_class;
136 GtkContainerClass *container_class;
138 widget_class = (GtkWidgetClass*) class;
139 container_class = (GtkContainerClass*) class;
141 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
143 widget_class->realize = gtk_socket_realize;
144 widget_class->unrealize = gtk_socket_unrealize;
145 widget_class->size_request = gtk_socket_size_request;
146 widget_class->size_allocate = gtk_socket_size_allocate;
147 widget_class->hierarchy_changed = gtk_socket_hierarchy_changed;
148 widget_class->grab_notify = gtk_socket_grab_notify;
149 widget_class->key_press_event = gtk_socket_key_press_event;
150 widget_class->focus_in_event = gtk_socket_focus_in_event;
151 widget_class->focus_out_event = gtk_socket_focus_out_event;
152 widget_class->focus = gtk_socket_focus;
154 container_class->remove = gtk_socket_remove;
155 container_class->forall = gtk_socket_forall;
157 socket_signals[PLUG_ADDED] =
158 g_signal_new ("plug_added",
159 G_OBJECT_CLASS_TYPE (class),
161 G_STRUCT_OFFSET (GtkSocketClass, plug_added),
163 gtk_marshal_VOID__VOID,
165 socket_signals[PLUG_REMOVED] =
166 g_signal_new ("plug_removed",
167 G_OBJECT_CLASS_TYPE (class),
169 G_STRUCT_OFFSET (GtkSocketClass, plug_removed),
170 _gtk_boolean_handled_accumulator, NULL,
171 gtk_marshal_BOOLEAN__VOID,
176 gtk_socket_init (GtkSocket *socket)
178 socket->request_width = 0;
179 socket->request_height = 0;
180 socket->current_width = 0;
181 socket->current_height = 0;
183 socket->plug_window = NULL;
184 socket->plug_widget = NULL;
185 socket->focus_in = FALSE;
186 socket->have_size = FALSE;
187 socket->need_map = FALSE;
194 * Create a new empty #GtkSocket.
196 * Return value: the new #GtkSocket.
199 gtk_socket_new (void)
203 socket = g_object_new (GTK_TYPE_SOCKET, NULL);
205 return GTK_WIDGET (socket);
210 * @socket: a #GtkSocket
211 * @id: the XID of an existing toplevel window.
213 * Reparents a pre-existing toplevel window into a #GtkSocket. This is
214 * meant to embed clients that do not know about embedding into a
215 * #GtkSocket, however doing so is inherently unreliable, and using
216 * this function is not recommended.
218 * The #GtkSocket must have already be added into a toplevel window
219 * before you can make this call.
222 gtk_socket_steal (GtkSocket *socket, GdkNativeWindow id)
224 g_return_if_fail (GTK_IS_SOCKET (socket));
225 g_return_if_fail (GTK_WIDGET_ANCHORED (socket));
227 if (!GTK_WIDGET_REALIZED (socket))
228 gtk_widget_realize (GTK_WIDGET (socket));
230 gtk_socket_add_window (socket, id, TRUE);
235 * @socket: a #GtkSocket
236 * @id: the XID of a client participating in the XEMBED protocol.
238 * Adds an XEMBED client, such as a #GtkPlug, to the #GtkSocket. The
239 * client may be in the same process or in a different process.
241 * To embed a #GtkPlug in a #GtkSocket, you can either create the
242 * #GtkPlug with gtk_plug_new (0), call gtk_plug_get_id() to get the
243 * window ID of the plug, and then pass that to the
244 * gtk_socket_add_id(), or you can call gtk_socket_get_id() to get the
245 * window ID for the socket, and call gtk_plug_new() passing in that
248 * The #GtkSocket must have already be added into a toplevel window
249 * before you can make this call.
252 gtk_socket_add_id (GtkSocket *socket, GdkNativeWindow id)
254 g_return_if_fail (GTK_IS_SOCKET (socket));
255 g_return_if_fail (GTK_WIDGET_ANCHORED (socket));
257 if (!GTK_WIDGET_REALIZED (socket))
258 gtk_widget_realize (GTK_WIDGET (socket));
260 gtk_socket_add_window (socket, id, TRUE);
265 * @socket: a #GtkSocket.
267 * Gets the window ID of a #GtkSocket widget, which can then
268 * be used to create a client embedded inside the socket, for
269 * instance with gtk_socket_new (id). The #GtkSocket must
270 * have already be added into a toplevel window before you
271 * can make this call.
273 * Return value: the window ID for the socket
276 gtk_socket_get_id (GtkSocket *socket)
278 g_return_val_if_fail (GTK_IS_SOCKET (socket), 0);
279 g_return_val_if_fail (GTK_WIDGET_ANCHORED (socket), 0);
281 if (!GTK_WIDGET_REALIZED (socket))
282 gtk_widget_realize (GTK_WIDGET (socket));
284 return GDK_WINDOW_XWINDOW (GTK_WIDGET (socket)->window);
288 gtk_socket_realize (GtkWidget *widget)
291 GdkWindowAttr attributes;
292 gint attributes_mask;
293 XWindowAttributes xattrs;
295 g_return_if_fail (widget != NULL);
296 g_return_if_fail (GTK_IS_SOCKET (widget));
298 socket = GTK_SOCKET (widget);
299 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
301 attributes.window_type = GDK_WINDOW_CHILD;
302 attributes.x = widget->allocation.x;
303 attributes.y = widget->allocation.y;
304 attributes.width = widget->allocation.width;
305 attributes.height = widget->allocation.height;
306 attributes.wclass = GDK_INPUT_OUTPUT;
307 attributes.visual = gtk_widget_get_visual (widget);
308 attributes.colormap = gtk_widget_get_colormap (widget);
309 attributes.event_mask = GDK_FOCUS_CHANGE_MASK;
311 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
313 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
314 &attributes, attributes_mask);
315 gdk_window_set_user_data (widget->window, socket);
317 widget->style = gtk_style_attach (widget->style, widget->window);
318 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
320 XGetWindowAttributes (GDK_DISPLAY (),
321 GDK_WINDOW_XWINDOW (widget->window),
324 XSelectInput (GDK_DISPLAY (),
325 GDK_WINDOW_XWINDOW(widget->window),
326 xattrs.your_event_mask |
327 SubstructureNotifyMask | SubstructureRedirectMask);
329 gdk_window_add_filter (widget->window, gtk_socket_filter_func, widget);
331 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
333 /* We sync here so that we make sure that if the XID for
334 * our window is passed to another application, SubstructureRedirectMask
335 * will be set by the time the other app creates its window.
341 gtk_socket_unrealize (GtkWidget *widget)
343 GtkSocket *socket = GTK_SOCKET (widget);
345 if (socket->plug_widget)
347 _gtk_plug_remove_from_socket (GTK_PLUG (socket->plug_widget), socket);
349 else if (socket->plug_window)
351 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
352 if (toplevel && GTK_IS_WINDOW (toplevel))
353 gtk_window_remove_embedded_xid (GTK_WINDOW (toplevel),
354 GDK_WINDOW_XWINDOW (socket->plug_window));
356 g_object_unref (socket->plug_window);
357 socket->plug_window = NULL;
361 if (socket->grabbed_keys)
363 g_hash_table_foreach (socket->grabbed_keys, (GHFunc)g_free, NULL);
364 g_hash_table_destroy (socket->grabbed_keys);
365 socket->grabbed_keys = NULL;
369 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
370 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
374 gtk_socket_size_request (GtkWidget *widget,
375 GtkRequisition *requisition)
377 GtkSocket *socket = GTK_SOCKET (widget);
379 if (socket->plug_widget)
381 gtk_widget_size_request (socket->plug_widget, requisition);
385 if (socket->is_mapped && !socket->have_size && socket->plug_window)
390 gdk_error_trap_push ();
392 if (XGetWMNormalHints (GDK_DISPLAY(),
393 GDK_WINDOW_XWINDOW (socket->plug_window),
396 /* This is obsolete, according the X docs, but many programs
398 if (hints.flags & (PSize | USSize))
400 socket->request_width = hints.width;
401 socket->request_height = hints.height;
403 else if (hints.flags & PMinSize)
405 socket->request_width = hints.min_width;
406 socket->request_height = hints.min_height;
408 else if (hints.flags & PBaseSize)
410 socket->request_width = hints.base_width;
411 socket->request_height = hints.base_height;
414 socket->have_size = TRUE; /* don't check again? */
416 gdk_error_trap_pop ();
419 if (socket->is_mapped && socket->have_size)
421 requisition->width = MAX (socket->request_width, 1);
422 requisition->height = MAX (socket->request_height, 1);
426 requisition->width = 1;
427 requisition->height = 1;
433 gtk_socket_size_allocate (GtkWidget *widget,
434 GtkAllocation *allocation)
438 g_return_if_fail (widget != NULL);
439 g_return_if_fail (GTK_IS_SOCKET (widget));
440 g_return_if_fail (allocation != NULL);
442 socket = GTK_SOCKET (widget);
444 widget->allocation = *allocation;
445 if (GTK_WIDGET_REALIZED (widget))
447 gdk_window_move_resize (widget->window,
448 allocation->x, allocation->y,
449 allocation->width, allocation->height);
451 if (socket->plug_widget)
453 GtkAllocation child_allocation;
455 child_allocation.x = 0;
456 child_allocation.y = 0;
457 child_allocation.width = allocation->width;
458 child_allocation.height = allocation->height;
460 gtk_widget_size_allocate (socket->plug_widget, &child_allocation);
462 else if (socket->plug_window)
464 gdk_error_trap_push ();
466 if (!socket->need_map &&
467 (allocation->width == socket->current_width) &&
468 (allocation->height == socket->current_height))
470 gtk_socket_send_configure_event (socket);
472 g_message ("GtkSocket - allocated no change: %d %d",
473 allocation->width, allocation->height));
477 gdk_window_move_resize (socket->plug_window,
479 allocation->width, allocation->height);
481 g_message ("GtkSocket - allocated: %d %d",
482 allocation->width, allocation->height));
483 socket->current_width = allocation->width;
484 socket->current_height = allocation->height;
487 if (socket->need_map)
489 gdk_window_show (socket->plug_window);
490 socket->need_map = FALSE;
494 gdk_error_trap_pop ();
503 guint accelerator_key;
504 GdkModifierType accelerator_mods;
508 grabbed_key_hash (gconstpointer a)
510 const GrabbedKey *key = a;
513 h = key->accelerator_key << 16;
514 h ^= key->accelerator_key >> 16;
515 h ^= key->accelerator_mods;
521 grabbed_key_equal (gconstpointer a, gconstpointer b)
523 const GrabbedKey *keya = a;
524 const GrabbedKey *keyb = b;
526 return (keya->accelerator_key == keyb->accelerator_key &&
527 keya->accelerator_mods == keyb->accelerator_mods);
531 add_grabbed_key (GtkSocket *socket,
532 guint hardware_keycode,
533 GdkModifierType mods)
537 GrabbedKey *found_key;
539 if (socket->grabbed_keys)
541 key.accelerator_key = hardware_keycode;
542 key.accelerator_mods = mods;
544 found_key = g_hash_table_lookup (socket->grabbed_keys, &key);
548 g_warning ("GtkSocket: request to add already present grabbed key %u,%#x\n",
549 hardware_keycode, mods);
554 if (!socket->grabbed_keys)
555 socket->grabbed_keys = g_hash_table_new (grabbed_key_hash, grabbed_key_equal);
557 new_key = g_new (GrabbedKey, 1);
559 new_key->accelerator_key = hardware_keycode;
560 new_key->accelerator_mods = mods;
562 g_hash_table_insert (socket->grabbed_keys, new_key, new_key);
566 remove_grabbed_key (GtkSocket *socket,
567 guint hardware_keycode,
568 GdkModifierType mods)
571 GrabbedKey *found_key = NULL;
573 if (socket->grabbed_keys)
575 key.accelerator_key = hardware_keycode;
576 key.accelerator_mods = mods;
578 found_key = g_hash_table_lookup (socket->grabbed_keys, &key);
583 g_hash_table_remove (socket->grabbed_keys, &key);
587 g_warning ("GtkSocket: request to remove non-present grabbed key %u,%#x\n",
588 hardware_keycode, mods);
592 toplevel_key_press_handler (GtkWidget *toplevel,
596 GrabbedKey search_key;
598 search_key.accelerator_key = event->hardware_keycode;
599 search_key.accelerator_mods = event->state;
601 if (socket->grabbed_keys &&
602 g_hash_table_lookup (socket->grabbed_keys, &search_key))
604 gtk_socket_key_press_event (GTK_WIDGET (socket), event);
605 gtk_signal_emit_stop_by_name (GTK_OBJECT (toplevel), "key_press_event");
616 toplevel_focus_in_handler (GtkWidget *toplevel,
617 GdkEventFocus *event,
620 /* It appears spurious focus in events can occur when
621 * the window is hidden. So we'll just check to see if
622 * the window is visible before actually handling the
623 * event. (Comment from gtkwindow.c)
625 if (GTK_WIDGET_VISIBLE (toplevel))
626 send_xembed_message (socket, XEMBED_WINDOW_ACTIVATE, 0, 0, 0,
627 gtk_get_current_event_time ()); /* Will be GDK_CURRENT_TIME */
631 toplevel_focus_out_handler (GtkWidget *toplevel,
632 GdkEventFocus *event,
635 send_xembed_message (socket, XEMBED_WINDOW_DEACTIVATE, 0, 0, 0,
636 gtk_get_current_event_time ()); /* Will be GDK_CURRENT_TIME */
640 gtk_socket_hierarchy_changed (GtkWidget *widget,
641 GtkWidget *old_toplevel)
643 GtkSocket *socket = GTK_SOCKET (widget);
644 GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
646 if (toplevel && !GTK_IS_WINDOW (toplevel))
649 if (toplevel != socket->toplevel)
651 if (socket->toplevel)
654 gtk_signal_disconnect_by_func (GTK_OBJECT (socket->toplevel), GTK_SIGNAL_FUNC (toplevel_key_press_handler), socket);
656 gtk_signal_disconnect_by_func (GTK_OBJECT (socket->toplevel), GTK_SIGNAL_FUNC (toplevel_focus_in_handler), socket);
657 gtk_signal_disconnect_by_func (GTK_OBJECT (socket->toplevel), GTK_SIGNAL_FUNC (toplevel_focus_out_handler), socket);
660 socket->toplevel = toplevel;
665 gtk_signal_connect (GTK_OBJECT (socket->toplevel), "key_press_event",
666 GTK_SIGNAL_FUNC (toplevel_key_press_handler), socket);
668 gtk_signal_connect (GTK_OBJECT (socket->toplevel), "focus_in_event",
669 GTK_SIGNAL_FUNC (toplevel_focus_in_handler), socket);
670 gtk_signal_connect (GTK_OBJECT (socket->toplevel), "focus_out_event",
671 GTK_SIGNAL_FUNC (toplevel_focus_out_handler), socket);
677 gtk_socket_grab_notify (GtkWidget *widget,
678 gboolean was_grabbed)
680 send_xembed_message (GTK_SOCKET (widget),
681 was_grabbed ? XEMBED_MODALITY_OFF : XEMBED_MODALITY_ON,
682 0, 0, 0, gtk_get_current_event_time ());
686 gtk_socket_key_press_event (GtkWidget *widget,
689 GtkSocket *socket = GTK_SOCKET (widget);
691 if (socket->plug_window)
695 xevent.xkey.type = KeyPress;
696 xevent.xkey.display = GDK_WINDOW_XDISPLAY (event->window);
697 xevent.xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
698 xevent.xkey.root = GDK_ROOT_WINDOW ();
699 xevent.xkey.time = event->time;
700 /* FIXME, the following might cause problems for non-GTK apps */
703 xevent.xkey.x_root = 0;
704 xevent.xkey.y_root = 0;
705 xevent.xkey.state = event->state;
706 xevent.xkey.keycode = event->hardware_keycode;
707 xevent.xkey.same_screen = TRUE; /* FIXME ? */
709 gdk_error_trap_push ();
710 XSendEvent (gdk_display,
711 GDK_WINDOW_XWINDOW (socket->plug_window),
712 False, NoEventMask, &xevent);
714 gdk_error_trap_pop ();
723 gtk_socket_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
725 GtkSocket *socket = GTK_SOCKET (widget);
727 if (!GTK_WIDGET_HAS_FOCUS (widget))
729 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
731 if (socket->plug_window)
733 send_xembed_message (socket, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT, 0, 0,
734 gtk_get_current_event_time ());
742 gtk_socket_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
744 GtkSocket *socket = GTK_SOCKET (widget);
746 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
750 toplevel = gtk_widget_get_toplevel (widget);
752 if (toplevel && GTK_IS_WINDOW (toplevel))
754 XSetInputFocus (GDK_DISPLAY (),
755 GDK_WINDOW_XWINDOW (toplevel->window),
756 RevertToParent, CurrentTime); /* FIXME? */
761 if (socket->plug_window)
763 send_xembed_message (socket, XEMBED_FOCUS_OUT, 0, 0, 0,
764 gtk_get_current_event_time ());
767 socket->focus_in = FALSE;
773 gtk_socket_claim_focus (GtkSocket *socket)
776 socket->focus_in = TRUE;
778 /* Oh, the trickery... */
780 GTK_WIDGET_SET_FLAGS (socket, GTK_CAN_FOCUS);
781 gtk_widget_grab_focus (GTK_WIDGET (socket));
782 GTK_WIDGET_UNSET_FLAGS (socket, GTK_CAN_FOCUS);
784 /* FIXME: we might grab the focus even if we don't have
785 * it as an app... (and see _focus_in ()) */
786 if (socket->plug_window)
789 gdk_error_trap_push ();
790 XSetInputFocus (GDK_DISPLAY (),
791 GDK_WINDOW_XWINDOW (socket->plug_window),
792 RevertToParent, GDK_CURRENT_TIME);
794 gdk_error_trap_pop ();
800 gtk_socket_focus (GtkWidget *widget, GtkDirectionType direction)
805 g_return_val_if_fail (GTK_IS_SOCKET (widget), FALSE);
807 socket = GTK_SOCKET (widget);
809 if (socket->plug_widget)
810 return gtk_widget_child_focus (socket->plug_widget, direction);
812 if (!GTK_WIDGET_HAS_FOCUS (widget))
818 case GTK_DIR_TAB_BACKWARD:
819 detail = XEMBED_FOCUS_LAST;
823 case GTK_DIR_TAB_FORWARD:
824 detail = XEMBED_FOCUS_FIRST;
828 send_xembed_message (socket, XEMBED_FOCUS_IN, detail, 0, 0,
829 gtk_get_current_event_time ());
831 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
832 gtk_widget_grab_focus (widget);
840 if (!socket->focus_in && socket->plug_window)
844 gtk_socket_claim_focus (socket);
846 xevent.xkey.type = KeyPress;
847 xevent.xkey.display = GDK_DISPLAY ();
848 xevent.xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
849 xevent.xkey.root = GDK_ROOT_WINDOW (); /* FIXME */
850 xevent.xkey.time = GDK_CURRENT_TIME; /* FIXME */
851 /* FIXME, the following might cause big problems for
855 xevent.xkey.x_root = 0;
856 xevent.xkey.y_root = 0;
857 xevent.xkey.state = 0;
858 xevent.xkey.same_screen = TRUE; /* FIXME ? */
863 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Up);
866 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Down);
869 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Left);
872 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Right);
874 case GTK_DIR_TAB_FORWARD:
875 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Tab);
877 case GTK_DIR_TAB_BACKWARD:
878 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Tab);
879 xevent.xkey.state = ShiftMask;
884 gdk_error_trap_push ();
885 XSendEvent (gdk_display,
886 GDK_WINDOW_XWINDOW (socket->plug_window),
887 False, NoEventMask, &xevent);
889 gdk_error_trap_pop ();
901 gtk_socket_remove (GtkContainer *container,
904 GtkSocket *socket = GTK_SOCKET (container);
906 g_return_if_fail (child == socket->plug_widget);
908 _gtk_plug_remove_from_socket (GTK_PLUG (socket->plug_widget), socket);
912 gtk_socket_forall (GtkContainer *container,
913 gboolean include_internals,
914 GtkCallback callback,
915 gpointer callback_data)
917 GtkSocket *socket = GTK_SOCKET (container);
919 if (socket->plug_widget)
920 (* callback) (socket->plug_widget, callback_data);
924 gtk_socket_send_configure_event (GtkSocket *socket)
928 g_return_if_fail (socket->plug_window != NULL);
930 event.xconfigure.type = ConfigureNotify;
931 event.xconfigure.display = gdk_display;
933 event.xconfigure.event = GDK_WINDOW_XWINDOW (socket->plug_window);
934 event.xconfigure.window = GDK_WINDOW_XWINDOW (socket->plug_window);
936 event.xconfigure.x = 0;
937 event.xconfigure.y = 0;
938 event.xconfigure.width = GTK_WIDGET(socket)->allocation.width;
939 event.xconfigure.height = GTK_WIDGET(socket)->allocation.height;
941 event.xconfigure.border_width = 0;
942 event.xconfigure.above = None;
943 event.xconfigure.override_redirect = False;
945 gdk_error_trap_push ();
946 XSendEvent (gdk_display,
947 GDK_WINDOW_XWINDOW (socket->plug_window),
948 False, NoEventMask, &event);
950 gdk_error_trap_pop ();
954 gtk_socket_add_window (GtkSocket *socket,
956 gboolean need_reparent)
959 GtkWidget *widget = GTK_WIDGET (socket);
960 gpointer user_data = NULL;
962 socket->plug_window = gdk_window_lookup (xid);
964 if (socket->plug_window)
966 g_object_ref (socket->plug_window);
967 gdk_window_get_user_data (socket->plug_window, &user_data);
970 if (user_data) /* A widget's window in this process */
972 GtkWidget *child_widget = user_data;
974 if (!GTK_IS_PLUG (child_widget))
976 g_warning (G_STRLOC "Can't add non-GtkPlug to GtkSocket");
977 socket->plug_window = NULL;
978 gdk_error_trap_pop ();
983 _gtk_plug_add_to_socket (GTK_PLUG (child_widget), socket);
985 else /* A foreign window */
988 GdkDragProtocol protocol;
989 unsigned long version;
992 gdk_error_trap_push ();
994 if (!socket->plug_window)
996 socket->plug_window = gdk_window_foreign_new (xid);
997 if (!socket->plug_window) /* was deleted before we could get it */
999 gdk_error_trap_pop ();
1004 XSelectInput (GDK_DISPLAY (),
1005 GDK_WINDOW_XWINDOW(socket->plug_window),
1006 StructureNotifyMask | PropertyChangeMask);
1008 if (gdk_error_trap_pop ())
1010 gdk_window_unref (socket->plug_window);
1011 socket->plug_window = NULL;
1015 /* OK, we now will reliably get destroy notification on socket->plug_window */
1017 gdk_error_trap_push ();
1021 gdk_window_hide (socket->plug_window); /* Shouldn't actually be necessary for XEMBED, but just in case */
1022 gdk_window_reparent (socket->plug_window, widget->window, 0, 0);
1025 socket->have_size = FALSE;
1027 socket->xembed_version = -1;
1028 if (xembed_get_info (socket->plug_window, &version, &flags))
1030 socket->xembed_version = version;
1031 socket->is_mapped = (flags & XEMBED_MAPPED) != 0;
1035 /* FIXME, we should probably actually check the state before we started */
1037 socket->is_mapped = need_reparent ? TRUE : FALSE;
1040 socket->need_map = socket->is_mapped;
1042 if (gdk_drag_get_protocol (xid, &protocol))
1043 gtk_drag_dest_set_proxy (GTK_WIDGET (socket), socket->plug_window,
1047 gdk_error_trap_pop ();
1049 gdk_window_add_filter (socket->plug_window,
1050 gtk_socket_filter_func, socket);
1052 /* Add a pointer to the socket on our toplevel window */
1054 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
1055 if (toplevel && GTK_IS_WINDOW (toplevel))
1056 gtk_window_add_embedded_xid (GTK_WINDOW (toplevel), xid);
1058 gtk_widget_queue_resize (GTK_WIDGET (socket));
1061 if (socket->plug_window)
1062 g_signal_emit (G_OBJECT (socket), socket_signals[PLUG_ADDED], 0);
1067 send_xembed_message (GtkSocket *socket,
1074 GTK_NOTE(PLUGSOCKET,
1075 g_message ("GtkSocket: Sending XEMBED message of type %d", message));
1077 if (socket->plug_window)
1081 xevent.xclient.window = GDK_WINDOW_XWINDOW (socket->plug_window);
1082 xevent.xclient.type = ClientMessage;
1083 xevent.xclient.message_type = gdk_atom_intern ("_XEMBED", FALSE);
1084 xevent.xclient.format = 32;
1085 xevent.xclient.data.l[0] = time;
1086 xevent.xclient.data.l[1] = message;
1087 xevent.xclient.data.l[2] = detail;
1088 xevent.xclient.data.l[3] = data1;
1089 xevent.xclient.data.l[4] = data2;
1091 gdk_error_trap_push ();
1092 XSendEvent (gdk_display,
1093 GDK_WINDOW_XWINDOW (socket->plug_window),
1094 False, NoEventMask, &xevent);
1096 gdk_error_trap_pop ();
1101 xembed_get_info (GdkWindow *gdk_window,
1102 unsigned long *version,
1103 unsigned long *flags)
1105 Display *display = GDK_WINDOW_XDISPLAY (gdk_window);
1106 Window window = GDK_WINDOW_XWINDOW (gdk_window);
1107 Atom xembed_info_atom = gdk_atom_intern ("_XEMBED_INFO", FALSE);
1110 unsigned long nitems, bytes_after;
1111 unsigned char *data;
1112 unsigned long *data_long;
1115 gdk_error_trap_push();
1116 status = XGetWindowProperty (display, window,
1119 xembed_info_atom, &type, &format,
1120 &nitems, &bytes_after, &data);
1121 gdk_error_trap_pop();
1123 if (status != Success)
1124 return FALSE; /* Window vanished? */
1126 if (type == None) /* No info property */
1129 if (type != xembed_info_atom)
1131 g_warning ("_XEMBED_INFO property has wrong type\n");
1137 g_warning ("_XEMBED_INFO too short\n");
1142 data_long = (unsigned long *)data;
1144 *version = data_long[0];
1146 *flags = data_long[1] & XEMBED_MAPPED;
1153 handle_xembed_message (GtkSocket *socket,
1162 case XEMBED_EMBEDDED_NOTIFY:
1163 case XEMBED_WINDOW_ACTIVATE:
1164 case XEMBED_WINDOW_DEACTIVATE:
1165 case XEMBED_MODALITY_ON:
1166 case XEMBED_MODALITY_OFF:
1167 case XEMBED_FOCUS_IN:
1168 case XEMBED_FOCUS_OUT:
1169 g_warning ("GtkSocket: Invalid _XEMBED message of type %ld received", message);
1172 case XEMBED_REQUEST_FOCUS:
1173 gtk_socket_claim_focus (socket);
1176 case XEMBED_FOCUS_NEXT:
1177 case XEMBED_FOCUS_PREV:
1179 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
1182 gtk_widget_child_focus (toplevel,
1183 (message == XEMBED_FOCUS_NEXT ?
1184 GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD));
1189 case XEMBED_GRAB_KEY:
1191 add_grabbed_key (socket, data1, data2);
1194 case XEMBED_UNGRAB_KEY:
1196 remove_grabbed_key (socket, data1, data2);
1201 GTK_NOTE(PLUGSOCKET,
1202 g_message ("GtkSocket: Ignoring unknown _XEMBED message of type %ld", message));
1208 map_request (GtkSocket *socket)
1210 if (!socket->is_mapped)
1212 socket->is_mapped = TRUE;
1213 socket->need_map = TRUE;
1215 gtk_widget_queue_resize (GTK_WIDGET (socket));
1220 unmap_notify (GtkSocket *socket)
1222 if (socket->is_mapped)
1224 socket->is_mapped = FALSE;
1225 gtk_widget_queue_resize (GTK_WIDGET (socket));
1229 static GdkFilterReturn
1230 gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
1236 GdkFilterReturn return_val;
1238 socket = GTK_SOCKET (data);
1239 widget = GTK_WIDGET (socket);
1240 xevent = (XEvent *)gdk_xevent;
1242 return_val = GDK_FILTER_CONTINUE;
1244 if (socket->plug_widget)
1247 switch (xevent->type)
1250 if (xevent->xclient.message_type == gdk_atom_intern ("_XEMBED", FALSE))
1252 handle_xembed_message (socket,
1253 xevent->xclient.data.l[1],
1254 xevent->xclient.data.l[2],
1255 xevent->xclient.data.l[3],
1256 xevent->xclient.data.l[4],
1257 xevent->xclient.data.l[0]);
1260 return_val = GDK_FILTER_REMOVE;
1266 XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
1268 if (!socket->plug_window)
1270 gtk_socket_add_window (socket, xcwe->window, FALSE);
1272 if (socket->plug_window)
1274 socket->request_width = xcwe->width;
1275 socket->request_height = xcwe->height;
1276 socket->have_size = TRUE;
1278 GTK_NOTE(PLUGSOCKET,
1279 g_message ("GtkSocket - window created with size: %d %d",
1280 socket->request_width,
1281 socket->request_height));
1285 return_val = GDK_FILTER_REMOVE;
1290 case ConfigureRequest:
1292 XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
1294 if (!socket->plug_window)
1295 gtk_socket_add_window (socket, xcre->window, FALSE);
1297 if (socket->plug_window)
1299 if (xcre->value_mask & (CWWidth | CWHeight))
1301 socket->request_width = xcre->width;
1302 socket->request_height = xcre->height;
1303 socket->have_size = TRUE;
1305 GTK_NOTE(PLUGSOCKET,
1306 g_message ("GtkSocket - configure request: %d %d",
1307 socket->request_width,
1308 socket->request_height));
1310 gtk_widget_queue_resize (widget);
1312 else if (xcre->value_mask & (CWX | CWY))
1314 gtk_socket_send_configure_event (socket);
1316 /* Ignore stacking requests. */
1318 return_val = GDK_FILTER_REMOVE;
1325 XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
1327 /* Note that we get destroy notifies both from SubstructureNotify on
1328 * our window and StructureNotify on socket->plug_window
1330 if (socket->plug_window && (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window)))
1332 GtkWidget *toplevel;
1335 GTK_NOTE(PLUGSOCKET,
1336 g_message ("GtkSocket - destroy notify"));
1338 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
1339 if (toplevel && GTK_IS_WINDOW (toplevel))
1340 gtk_window_remove_embedded_xid (GTK_WINDOW (toplevel), xdwe->window);
1342 gdk_window_destroy_notify (socket->plug_window);
1343 g_object_unref (socket->plug_window);
1344 socket->plug_window = NULL;
1346 g_object_ref (widget);
1347 g_signal_emit (G_OBJECT (widget), socket_signals[PLUG_REMOVED], 0, &result);
1349 gtk_widget_destroy (widget);
1350 g_object_unref (widget);
1352 return_val = GDK_FILTER_REMOVE;
1358 if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
1360 gtk_socket_claim_focus (socket);
1362 else if (xevent->xfocus.detail == NotifyInferior)
1365 GtkWidget *toplevel;
1366 toplevel = gtk_widget_get_toplevel (widget);
1368 if (toplevel && GTK_IS_WINDOW (topelevel))
1370 XSetInputFocus (GDK_DISPLAY (),
1371 GDK_WINDOW_XWINDOW (toplevel->window),
1372 RevertToParent, CurrentTime); /* FIXME? */
1376 return_val = GDK_FILTER_REMOVE;
1379 return_val = GDK_FILTER_REMOVE;
1382 if (!socket->plug_window)
1383 gtk_socket_add_window (socket, xevent->xmaprequest.window, FALSE);
1385 if (socket->plug_window)
1387 GTK_NOTE(PLUGSOCKET,
1388 g_message ("GtkSocket - Map Request"));
1390 map_request (socket);
1391 return_val = GDK_FILTER_REMOVE;
1394 case PropertyNotify:
1395 if (socket->plug_window &&
1396 xevent->xproperty.window == GDK_WINDOW_XWINDOW (socket->plug_window))
1398 GdkDragProtocol protocol;
1400 if ((xevent->xproperty.atom == gdk_atom_intern ("XdndAware", FALSE)) ||
1401 (xevent->xproperty.atom == gdk_atom_intern ("_MOTIF_DRAG_RECEIVER_INFO", FALSE)))
1403 gdk_error_trap_push ();
1404 if (gdk_drag_get_protocol (xevent->xproperty.window, &protocol))
1405 gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
1406 socket->plug_window,
1409 gdk_error_trap_pop ();
1411 else if (xevent->xproperty.atom == gdk_atom_intern ("_XEMBED_INFO", FALSE))
1413 unsigned long flags;
1415 if (xembed_get_info (socket->plug_window, NULL, &flags))
1417 gboolean was_mapped = socket->is_mapped;
1418 gboolean is_mapped = (flags & XEMBED_MAPPED) != 0;
1420 if (was_mapped != is_mapped)
1423 map_request (socket);
1426 gdk_error_trap_push ();
1427 gdk_window_show (socket->plug_window);
1429 gdk_error_trap_pop ();
1431 unmap_notify (socket);
1437 return_val = GDK_FILTER_REMOVE;
1440 case ReparentNotify:
1442 XReparentEvent *xre = &xevent->xreparent;
1444 if (!socket->plug_window && xre->parent == GDK_WINDOW_XWINDOW (widget->window))
1446 gtk_socket_add_window (socket, xre->window, FALSE);
1448 if (socket->plug_window)
1450 GTK_NOTE(PLUGSOCKET,
1451 g_message ("GtkSocket - window reparented",
1452 socket->request_width,
1453 socket->request_height));
1456 return_val = GDK_FILTER_REMOVE;
1462 if (socket->plug_window &&
1463 xevent->xunmap.window == GDK_WINDOW_XWINDOW (socket->plug_window))
1465 GTK_NOTE(PLUGSOCKET,
1466 g_message ("GtkSocket - Unmap notify"));
1468 unmap_notify (socket);
1469 return_val = GDK_FILTER_REMOVE;