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;
193 * Create a new empty #GtkSocket.
195 * Return value: the new #GtkSocket.
198 gtk_socket_new (void)
202 socket = g_object_new (GTK_TYPE_SOCKET, NULL);
204 return GTK_WIDGET (socket);
209 * @socket: a #GtkSocket
210 * @wid: the XID of an existing toplevel window.
212 * Reparents a pre-existing toplevel window into a #GtkSocket. This is
213 * meant to embed clients that do not know about embedding into a
214 * #GtkSocket, however doing so is inherently unreliable, and using
215 * this function is not recommended.
217 * The #GtkSocket must have already be added into a toplevel window
218 * before you can make this call.
221 gtk_socket_steal (GtkSocket *socket, GdkNativeWindow wid)
223 g_return_if_fail (GTK_IS_SOCKET (socket));
224 g_return_if_fail (GTK_WIDGET_ANCHORED (socket));
226 if (!GTK_WIDGET_REALIZED (socket))
227 gtk_widget_realize (GTK_WIDGET (socket));
229 gtk_socket_add_window (socket, wid, TRUE);
234 * @socket: a #GtkSocket
235 * @id: the XID of a client participating in the XEMBED protocol.
237 * Adds an XEMBED client, such as a #GtkPlug, to the #GtkSocket. The
238 * client may be in the same process or in a different process.
240 * To embed a #GtkPlug in a #GtkSocket, you can either create the
241 * #GtkPlug with gtk_plug_new (0), call gtk_plug_get_id() to get the
242 * window ID of the plug, and then pass that to the
243 * gtk_socket_add_id(), or you can call gtk_socket_get_id() to get the
244 * window ID for the socket, and call gtk_plug_new() passing in that
247 * The #GtkSocket must have already be added into a toplevel window
248 * before you can make this call.
251 gtk_socket_add_id (GtkSocket *socket, GdkNativeWindow id)
253 g_return_if_fail (GTK_IS_SOCKET (socket));
254 g_return_if_fail (GTK_WIDGET_ANCHORED (socket));
256 if (!GTK_WIDGET_REALIZED (socket))
257 gtk_widget_realize (GTK_WIDGET (socket));
259 gtk_socket_add_window (socket, id, TRUE);
264 * @socket: a #GtkSocket.
266 * Gets the window ID of a #GtkSocket widget, which can then
267 * be used to create a client embedded inside the socket, for
268 * instance with gtk_socket_new (id). The #GtkSocket must
269 * have already be added into a toplevel window before you
270 * can make this call.
272 * Return value: the window ID for the socket
275 gtk_socket_get_id (GtkSocket *socket)
277 g_return_val_if_fail (GTK_IS_SOCKET (socket), 0);
278 g_return_val_if_fail (GTK_WIDGET_ANCHORED (socket), 0);
280 if (!GTK_WIDGET_REALIZED (socket))
281 gtk_widget_realize (GTK_WIDGET (socket));
283 return GDK_WINDOW_XWINDOW (GTK_WIDGET (socket)->window);
287 gtk_socket_realize (GtkWidget *widget)
290 GdkWindowAttr attributes;
291 gint attributes_mask;
292 XWindowAttributes xattrs;
294 g_return_if_fail (GTK_IS_SOCKET (widget));
296 socket = GTK_SOCKET (widget);
297 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
299 attributes.window_type = GDK_WINDOW_CHILD;
300 attributes.x = widget->allocation.x;
301 attributes.y = widget->allocation.y;
302 attributes.width = widget->allocation.width;
303 attributes.height = widget->allocation.height;
304 attributes.wclass = GDK_INPUT_OUTPUT;
305 attributes.visual = gtk_widget_get_visual (widget);
306 attributes.colormap = gtk_widget_get_colormap (widget);
307 attributes.event_mask = GDK_FOCUS_CHANGE_MASK;
309 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
311 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
312 &attributes, attributes_mask);
313 gdk_window_set_user_data (widget->window, socket);
315 widget->style = gtk_style_attach (widget->style, widget->window);
316 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
318 XGetWindowAttributes (GDK_DISPLAY (),
319 GDK_WINDOW_XWINDOW (widget->window),
322 XSelectInput (GDK_DISPLAY (),
323 GDK_WINDOW_XWINDOW(widget->window),
324 xattrs.your_event_mask |
325 SubstructureNotifyMask | SubstructureRedirectMask);
327 gdk_window_add_filter (widget->window, gtk_socket_filter_func, widget);
329 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
331 /* We sync here so that we make sure that if the XID for
332 * our window is passed to another application, SubstructureRedirectMask
333 * will be set by the time the other app creates its window.
339 gtk_socket_unrealize (GtkWidget *widget)
341 GtkSocket *socket = GTK_SOCKET (widget);
343 GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED);
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 (GTK_IS_SOCKET (widget));
439 g_return_if_fail (allocation != NULL);
441 socket = GTK_SOCKET (widget);
443 widget->allocation = *allocation;
444 if (GTK_WIDGET_REALIZED (widget))
446 gdk_window_move_resize (widget->window,
447 allocation->x, allocation->y,
448 allocation->width, allocation->height);
450 if (socket->plug_widget)
452 GtkAllocation child_allocation;
454 child_allocation.x = 0;
455 child_allocation.y = 0;
456 child_allocation.width = allocation->width;
457 child_allocation.height = allocation->height;
459 gtk_widget_size_allocate (socket->plug_widget, &child_allocation);
461 else if (socket->plug_window)
463 gdk_error_trap_push ();
465 if (!socket->need_map &&
466 (allocation->width == socket->current_width) &&
467 (allocation->height == socket->current_height))
469 gtk_socket_send_configure_event (socket);
471 g_message ("GtkSocket - allocated no change: %d %d",
472 allocation->width, allocation->height));
476 gdk_window_move_resize (socket->plug_window,
478 allocation->width, allocation->height);
480 g_message ("GtkSocket - allocated: %d %d",
481 allocation->width, allocation->height));
482 socket->current_width = allocation->width;
483 socket->current_height = allocation->height;
486 if (socket->need_map)
488 gdk_window_show (socket->plug_window);
489 socket->need_map = FALSE;
493 gdk_error_trap_pop ();
502 guint accelerator_key;
503 GdkModifierType accelerator_mods;
507 grabbed_key_hash (gconstpointer a)
509 const GrabbedKey *key = a;
512 h = key->accelerator_key << 16;
513 h ^= key->accelerator_key >> 16;
514 h ^= key->accelerator_mods;
520 grabbed_key_equal (gconstpointer a, gconstpointer b)
522 const GrabbedKey *keya = a;
523 const GrabbedKey *keyb = b;
525 return (keya->accelerator_key == keyb->accelerator_key &&
526 keya->accelerator_mods == keyb->accelerator_mods);
530 add_grabbed_key (GtkSocket *socket,
531 guint hardware_keycode,
532 GdkModifierType mods)
536 GrabbedKey *found_key;
538 if (socket->grabbed_keys)
540 key.accelerator_key = hardware_keycode;
541 key.accelerator_mods = mods;
543 found_key = g_hash_table_lookup (socket->grabbed_keys, &key);
547 g_warning ("GtkSocket: request to add already present grabbed key %u,%#x\n",
548 hardware_keycode, mods);
553 if (!socket->grabbed_keys)
554 socket->grabbed_keys = g_hash_table_new (grabbed_key_hash, grabbed_key_equal);
556 new_key = g_new (GrabbedKey, 1);
558 new_key->accelerator_key = hardware_keycode;
559 new_key->accelerator_mods = mods;
561 g_hash_table_insert (socket->grabbed_keys, new_key, new_key);
565 remove_grabbed_key (GtkSocket *socket,
566 guint hardware_keycode,
567 GdkModifierType mods)
570 GrabbedKey *found_key = NULL;
572 if (socket->grabbed_keys)
574 key.accelerator_key = hardware_keycode;
575 key.accelerator_mods = mods;
577 found_key = g_hash_table_lookup (socket->grabbed_keys, &key);
582 g_hash_table_remove (socket->grabbed_keys, &key);
586 g_warning ("GtkSocket: request to remove non-present grabbed key %u,%#x\n",
587 hardware_keycode, mods);
591 toplevel_key_press_handler (GtkWidget *toplevel,
595 GrabbedKey search_key;
597 search_key.accelerator_key = event->hardware_keycode;
598 search_key.accelerator_mods = event->state;
600 if (socket->grabbed_keys &&
601 g_hash_table_lookup (socket->grabbed_keys, &search_key))
603 gtk_socket_key_press_event (GTK_WIDGET (socket), event);
604 gtk_signal_emit_stop_by_name (GTK_OBJECT (toplevel), "key_press_event");
615 toplevel_focus_in_handler (GtkWidget *toplevel,
616 GdkEventFocus *event,
619 /* It appears spurious focus in events can occur when
620 * the window is hidden. So we'll just check to see if
621 * the window is visible before actually handling the
622 * event. (Comment from gtkwindow.c)
624 if (GTK_WIDGET_VISIBLE (toplevel))
625 send_xembed_message (socket, XEMBED_WINDOW_ACTIVATE, 0, 0, 0,
626 gtk_get_current_event_time ()); /* Will be GDK_CURRENT_TIME */
630 toplevel_focus_out_handler (GtkWidget *toplevel,
631 GdkEventFocus *event,
634 send_xembed_message (socket, XEMBED_WINDOW_DEACTIVATE, 0, 0, 0,
635 gtk_get_current_event_time ()); /* Will be GDK_CURRENT_TIME */
639 gtk_socket_hierarchy_changed (GtkWidget *widget,
640 GtkWidget *old_toplevel)
642 GtkSocket *socket = GTK_SOCKET (widget);
643 GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
645 if (toplevel && !GTK_IS_WINDOW (toplevel))
648 if (toplevel != socket->toplevel)
650 if (socket->toplevel)
653 gtk_signal_disconnect_by_func (GTK_OBJECT (socket->toplevel), GTK_SIGNAL_FUNC (toplevel_key_press_handler), socket);
655 gtk_signal_disconnect_by_func (GTK_OBJECT (socket->toplevel), GTK_SIGNAL_FUNC (toplevel_focus_in_handler), socket);
656 gtk_signal_disconnect_by_func (GTK_OBJECT (socket->toplevel), GTK_SIGNAL_FUNC (toplevel_focus_out_handler), socket);
659 socket->toplevel = toplevel;
664 gtk_signal_connect (GTK_OBJECT (socket->toplevel), "key_press_event",
665 GTK_SIGNAL_FUNC (toplevel_key_press_handler), socket);
667 gtk_signal_connect (GTK_OBJECT (socket->toplevel), "focus_in_event",
668 GTK_SIGNAL_FUNC (toplevel_focus_in_handler), socket);
669 gtk_signal_connect (GTK_OBJECT (socket->toplevel), "focus_out_event",
670 GTK_SIGNAL_FUNC (toplevel_focus_out_handler), socket);
676 gtk_socket_grab_notify (GtkWidget *widget,
677 gboolean was_grabbed)
679 send_xembed_message (GTK_SOCKET (widget),
680 was_grabbed ? XEMBED_MODALITY_OFF : XEMBED_MODALITY_ON,
681 0, 0, 0, gtk_get_current_event_time ());
685 gtk_socket_key_press_event (GtkWidget *widget,
688 GtkSocket *socket = GTK_SOCKET (widget);
690 if (socket->plug_window)
694 xevent.xkey.type = KeyPress;
695 xevent.xkey.display = GDK_WINDOW_XDISPLAY (event->window);
696 xevent.xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
697 xevent.xkey.root = GDK_ROOT_WINDOW ();
698 xevent.xkey.time = event->time;
699 /* FIXME, the following might cause problems for non-GTK apps */
702 xevent.xkey.x_root = 0;
703 xevent.xkey.y_root = 0;
704 xevent.xkey.state = event->state;
705 xevent.xkey.keycode = event->hardware_keycode;
706 xevent.xkey.same_screen = TRUE; /* FIXME ? */
708 gdk_error_trap_push ();
709 XSendEvent (GDK_DISPLAY (),
710 GDK_WINDOW_XWINDOW (socket->plug_window),
711 False, NoEventMask, &xevent);
713 gdk_error_trap_pop ();
722 gtk_socket_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
724 GtkSocket *socket = GTK_SOCKET (widget);
726 if (!GTK_WIDGET_HAS_FOCUS (widget))
728 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
730 if (socket->plug_window)
732 send_xembed_message (socket, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT, 0, 0,
733 gtk_get_current_event_time ());
741 gtk_socket_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
743 GtkSocket *socket = GTK_SOCKET (widget);
745 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
749 toplevel = gtk_widget_get_toplevel (widget);
751 if (toplevel && GTK_IS_WINDOW (toplevel))
753 XSetInputFocus (GDK_DISPLAY (),
754 GDK_WINDOW_XWINDOW (toplevel->window),
755 RevertToParent, CurrentTime); /* FIXME? */
760 if (socket->plug_window)
762 send_xembed_message (socket, XEMBED_FOCUS_OUT, 0, 0, 0,
763 gtk_get_current_event_time ());
766 socket->focus_in = FALSE;
772 gtk_socket_claim_focus (GtkSocket *socket)
775 socket->focus_in = TRUE;
777 /* Oh, the trickery... */
779 GTK_WIDGET_SET_FLAGS (socket, GTK_CAN_FOCUS);
780 gtk_widget_grab_focus (GTK_WIDGET (socket));
781 GTK_WIDGET_UNSET_FLAGS (socket, GTK_CAN_FOCUS);
783 /* FIXME: we might grab the focus even if we don't have
784 * it as an app... (and see _focus_in ()) */
785 if (socket->plug_window)
788 gdk_error_trap_push ();
789 XSetInputFocus (GDK_DISPLAY (),
790 GDK_WINDOW_XWINDOW (socket->plug_window),
791 RevertToParent, GDK_CURRENT_TIME);
793 gdk_error_trap_pop ();
799 gtk_socket_focus (GtkWidget *widget, GtkDirectionType direction)
804 g_return_val_if_fail (GTK_IS_SOCKET (widget), FALSE);
806 socket = GTK_SOCKET (widget);
808 if (socket->plug_widget)
809 return gtk_widget_child_focus (socket->plug_widget, direction);
811 if (!GTK_WIDGET_HAS_FOCUS (widget))
817 case GTK_DIR_TAB_BACKWARD:
818 detail = XEMBED_FOCUS_LAST;
822 case GTK_DIR_TAB_FORWARD:
823 detail = XEMBED_FOCUS_FIRST;
827 send_xembed_message (socket, XEMBED_FOCUS_IN, detail, 0, 0,
828 gtk_get_current_event_time ());
830 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
831 gtk_widget_grab_focus (widget);
839 if (!socket->focus_in && socket->plug_window)
843 gtk_socket_claim_focus (socket);
845 xevent.xkey.type = KeyPress;
846 xevent.xkey.display = GDK_DISPLAY ();
847 xevent.xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
848 xevent.xkey.root = GDK_ROOT_WINDOW (); /* FIXME */
849 xevent.xkey.time = GDK_CURRENT_TIME; /* FIXME */
850 /* FIXME, the following might cause big problems for
854 xevent.xkey.x_root = 0;
855 xevent.xkey.y_root = 0;
856 xevent.xkey.state = 0;
857 xevent.xkey.same_screen = TRUE; /* FIXME ? */
862 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Up);
865 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Down);
868 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Left);
871 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Right);
873 case GTK_DIR_TAB_FORWARD:
874 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Tab);
876 case GTK_DIR_TAB_BACKWARD:
877 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(), GDK_Tab);
878 xevent.xkey.state = ShiftMask;
883 gdk_error_trap_push ();
884 XSendEvent (GDK_DISPLAY (),
885 GDK_WINDOW_XWINDOW (socket->plug_window),
886 False, NoEventMask, &xevent);
888 gdk_error_trap_pop ();
900 gtk_socket_remove (GtkContainer *container,
903 GtkSocket *socket = GTK_SOCKET (container);
905 g_return_if_fail (child == socket->plug_widget);
907 _gtk_plug_remove_from_socket (GTK_PLUG (socket->plug_widget), socket);
911 gtk_socket_forall (GtkContainer *container,
912 gboolean include_internals,
913 GtkCallback callback,
914 gpointer callback_data)
916 GtkSocket *socket = GTK_SOCKET (container);
918 if (socket->plug_widget)
919 (* callback) (socket->plug_widget, callback_data);
923 gtk_socket_send_configure_event (GtkSocket *socket)
927 g_return_if_fail (socket->plug_window != NULL);
929 event.xconfigure.type = ConfigureNotify;
930 event.xconfigure.display = GDK_DISPLAY ();
932 event.xconfigure.event = GDK_WINDOW_XWINDOW (socket->plug_window);
933 event.xconfigure.window = GDK_WINDOW_XWINDOW (socket->plug_window);
935 event.xconfigure.x = 0;
936 event.xconfigure.y = 0;
937 event.xconfigure.width = GTK_WIDGET(socket)->allocation.width;
938 event.xconfigure.height = GTK_WIDGET(socket)->allocation.height;
940 event.xconfigure.border_width = 0;
941 event.xconfigure.above = None;
942 event.xconfigure.override_redirect = False;
944 gdk_error_trap_push ();
945 XSendEvent (GDK_DISPLAY (),
946 GDK_WINDOW_XWINDOW (socket->plug_window),
947 False, NoEventMask, &event);
949 gdk_error_trap_pop ();
953 gtk_socket_add_window (GtkSocket *socket,
955 gboolean need_reparent)
958 GtkWidget *widget = GTK_WIDGET (socket);
959 gpointer user_data = NULL;
961 socket->plug_window = gdk_window_lookup (xid);
963 if (socket->plug_window)
965 g_object_ref (socket->plug_window);
966 gdk_window_get_user_data (socket->plug_window, &user_data);
969 if (user_data) /* A widget's window in this process */
971 GtkWidget *child_widget = user_data;
973 if (!GTK_IS_PLUG (child_widget))
975 g_warning (G_STRLOC "Can't add non-GtkPlug to GtkSocket");
976 socket->plug_window = NULL;
977 gdk_error_trap_pop ();
982 _gtk_plug_add_to_socket (GTK_PLUG (child_widget), socket);
984 else /* A foreign window */
987 GdkDragProtocol protocol;
988 unsigned long version;
991 gdk_error_trap_push ();
993 if (!socket->plug_window)
995 socket->plug_window = gdk_window_foreign_new (xid);
996 if (!socket->plug_window) /* was deleted before we could get it */
998 gdk_error_trap_pop ();
1003 XSelectInput (GDK_DISPLAY (),
1004 GDK_WINDOW_XWINDOW(socket->plug_window),
1005 StructureNotifyMask | PropertyChangeMask);
1007 if (gdk_error_trap_pop ())
1009 gdk_window_unref (socket->plug_window);
1010 socket->plug_window = NULL;
1014 /* OK, we now will reliably get destroy notification on socket->plug_window */
1016 gdk_error_trap_push ();
1020 gdk_window_hide (socket->plug_window); /* Shouldn't actually be necessary for XEMBED, but just in case */
1021 gdk_window_reparent (socket->plug_window, widget->window, 0, 0);
1024 socket->have_size = FALSE;
1026 socket->xembed_version = -1;
1027 if (xembed_get_info (socket->plug_window, &version, &flags))
1029 socket->xembed_version = version;
1030 socket->is_mapped = (flags & XEMBED_MAPPED) != 0;
1034 /* FIXME, we should probably actually check the state before we started */
1036 socket->is_mapped = need_reparent ? TRUE : FALSE;
1039 socket->need_map = socket->is_mapped;
1041 if (gdk_drag_get_protocol (xid, &protocol))
1042 gtk_drag_dest_set_proxy (GTK_WIDGET (socket), socket->plug_window,
1046 gdk_error_trap_pop ();
1048 gdk_window_add_filter (socket->plug_window,
1049 gtk_socket_filter_func, socket);
1051 /* Add a pointer to the socket on our toplevel window */
1053 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
1054 if (toplevel && GTK_IS_WINDOW (toplevel))
1055 gtk_window_add_embedded_xid (GTK_WINDOW (toplevel), xid);
1057 gtk_widget_queue_resize (GTK_WIDGET (socket));
1060 if (socket->plug_window)
1061 g_signal_emit (G_OBJECT (socket), socket_signals[PLUG_ADDED], 0);
1066 send_xembed_message (GtkSocket *socket,
1073 GTK_NOTE(PLUGSOCKET,
1074 g_message ("GtkSocket: Sending XEMBED message of type %d", message));
1076 if (socket->plug_window)
1080 xevent.xclient.window = GDK_WINDOW_XWINDOW (socket->plug_window);
1081 xevent.xclient.type = ClientMessage;
1082 xevent.xclient.message_type = gdk_x11_get_xatom_by_name ("_XEMBED");
1083 xevent.xclient.format = 32;
1084 xevent.xclient.data.l[0] = time;
1085 xevent.xclient.data.l[1] = message;
1086 xevent.xclient.data.l[2] = detail;
1087 xevent.xclient.data.l[3] = data1;
1088 xevent.xclient.data.l[4] = data2;
1090 gdk_error_trap_push ();
1091 XSendEvent (GDK_DISPLAY (),
1092 GDK_WINDOW_XWINDOW (socket->plug_window),
1093 False, NoEventMask, &xevent);
1095 gdk_error_trap_pop ();
1100 xembed_get_info (GdkWindow *gdk_window,
1101 unsigned long *version,
1102 unsigned long *flags)
1104 Display *display = GDK_WINDOW_XDISPLAY (gdk_window);
1105 Window window = GDK_WINDOW_XWINDOW (gdk_window);
1106 Atom xembed_info_atom = gdk_x11_get_xatom_by_name ("_XEMBED_INFO");
1109 unsigned long nitems, bytes_after;
1110 unsigned char *data;
1111 unsigned long *data_long;
1114 gdk_error_trap_push();
1115 status = XGetWindowProperty (display, window,
1118 xembed_info_atom, &type, &format,
1119 &nitems, &bytes_after, &data);
1120 gdk_error_trap_pop();
1122 if (status != Success)
1123 return FALSE; /* Window vanished? */
1125 if (type == None) /* No info property */
1128 if (type != xembed_info_atom)
1130 g_warning ("_XEMBED_INFO property has wrong type\n");
1136 g_warning ("_XEMBED_INFO too short\n");
1141 data_long = (unsigned long *)data;
1143 *version = data_long[0];
1145 *flags = data_long[1] & XEMBED_MAPPED;
1152 handle_xembed_message (GtkSocket *socket,
1161 case XEMBED_EMBEDDED_NOTIFY:
1162 case XEMBED_WINDOW_ACTIVATE:
1163 case XEMBED_WINDOW_DEACTIVATE:
1164 case XEMBED_MODALITY_ON:
1165 case XEMBED_MODALITY_OFF:
1166 case XEMBED_FOCUS_IN:
1167 case XEMBED_FOCUS_OUT:
1168 g_warning ("GtkSocket: Invalid _XEMBED message of type %ld received", message);
1171 case XEMBED_REQUEST_FOCUS:
1172 gtk_socket_claim_focus (socket);
1175 case XEMBED_FOCUS_NEXT:
1176 case XEMBED_FOCUS_PREV:
1178 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
1181 gtk_widget_child_focus (toplevel,
1182 (message == XEMBED_FOCUS_NEXT ?
1183 GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD));
1188 case XEMBED_GRAB_KEY:
1190 add_grabbed_key (socket, data1, data2);
1193 case XEMBED_UNGRAB_KEY:
1195 remove_grabbed_key (socket, data1, data2);
1200 GTK_NOTE(PLUGSOCKET,
1201 g_message ("GtkSocket: Ignoring unknown _XEMBED message of type %ld", message));
1207 map_request (GtkSocket *socket)
1209 if (!socket->is_mapped)
1211 socket->is_mapped = TRUE;
1212 socket->need_map = TRUE;
1214 gtk_widget_queue_resize (GTK_WIDGET (socket));
1219 unmap_notify (GtkSocket *socket)
1221 if (socket->is_mapped)
1223 socket->is_mapped = FALSE;
1224 gtk_widget_queue_resize (GTK_WIDGET (socket));
1228 static GdkFilterReturn
1229 gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
1235 GdkFilterReturn return_val;
1237 socket = GTK_SOCKET (data);
1238 widget = GTK_WIDGET (socket);
1239 xevent = (XEvent *)gdk_xevent;
1241 return_val = GDK_FILTER_CONTINUE;
1243 if (socket->plug_widget)
1246 switch (xevent->type)
1249 if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name ("_XEMBED"))
1251 handle_xembed_message (socket,
1252 xevent->xclient.data.l[1],
1253 xevent->xclient.data.l[2],
1254 xevent->xclient.data.l[3],
1255 xevent->xclient.data.l[4],
1256 xevent->xclient.data.l[0]);
1259 return_val = GDK_FILTER_REMOVE;
1265 XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
1267 if (!socket->plug_window)
1269 gtk_socket_add_window (socket, xcwe->window, FALSE);
1271 if (socket->plug_window)
1273 socket->request_width = xcwe->width;
1274 socket->request_height = xcwe->height;
1275 socket->have_size = TRUE;
1277 GTK_NOTE(PLUGSOCKET,
1278 g_message ("GtkSocket - window created with size: %d %d",
1279 socket->request_width,
1280 socket->request_height));
1284 return_val = GDK_FILTER_REMOVE;
1289 case ConfigureRequest:
1291 XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
1293 if (!socket->plug_window)
1294 gtk_socket_add_window (socket, xcre->window, FALSE);
1296 if (socket->plug_window)
1298 if (xcre->value_mask & (CWWidth | CWHeight))
1300 socket->request_width = xcre->width;
1301 socket->request_height = xcre->height;
1302 socket->have_size = TRUE;
1304 GTK_NOTE(PLUGSOCKET,
1305 g_message ("GtkSocket - configure request: %d %d",
1306 socket->request_width,
1307 socket->request_height));
1309 gtk_widget_queue_resize (widget);
1311 else if (xcre->value_mask & (CWX | CWY))
1313 gtk_socket_send_configure_event (socket);
1315 /* Ignore stacking requests. */
1317 return_val = GDK_FILTER_REMOVE;
1324 XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
1326 /* Note that we get destroy notifies both from SubstructureNotify on
1327 * our window and StructureNotify on socket->plug_window
1329 if (socket->plug_window && (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window)))
1331 GtkWidget *toplevel;
1334 GTK_NOTE(PLUGSOCKET,
1335 g_message ("GtkSocket - destroy notify"));
1337 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
1338 if (toplevel && GTK_IS_WINDOW (toplevel))
1339 gtk_window_remove_embedded_xid (GTK_WINDOW (toplevel), xdwe->window);
1341 gdk_window_destroy_notify (socket->plug_window);
1342 g_object_unref (socket->plug_window);
1343 socket->plug_window = NULL;
1345 g_object_ref (widget);
1346 g_signal_emit (G_OBJECT (widget), socket_signals[PLUG_REMOVED], 0, &result);
1348 gtk_widget_destroy (widget);
1349 g_object_unref (widget);
1351 return_val = GDK_FILTER_REMOVE;
1357 if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
1359 gtk_socket_claim_focus (socket);
1361 else if (xevent->xfocus.detail == NotifyInferior)
1364 GtkWidget *toplevel;
1365 toplevel = gtk_widget_get_toplevel (widget);
1367 if (toplevel && GTK_IS_WINDOW (topelevel))
1369 XSetInputFocus (GDK_DISPLAY (),
1370 GDK_WINDOW_XWINDOW (toplevel->window),
1371 RevertToParent, CurrentTime); /* FIXME? */
1375 return_val = GDK_FILTER_REMOVE;
1378 return_val = GDK_FILTER_REMOVE;
1381 if (!socket->plug_window)
1382 gtk_socket_add_window (socket, xevent->xmaprequest.window, FALSE);
1384 if (socket->plug_window)
1386 GTK_NOTE(PLUGSOCKET,
1387 g_message ("GtkSocket - Map Request"));
1389 map_request (socket);
1390 return_val = GDK_FILTER_REMOVE;
1393 case PropertyNotify:
1394 if (socket->plug_window &&
1395 xevent->xproperty.window == GDK_WINDOW_XWINDOW (socket->plug_window))
1397 GdkDragProtocol protocol;
1399 if ((xevent->xproperty.atom == gdk_x11_get_xatom_by_name ("XdndAware")) ||
1400 (xevent->xproperty.atom == gdk_x11_get_xatom_by_name ("_MOTIF_DRAG_RECEIVER_INFO")))
1402 gdk_error_trap_push ();
1403 if (gdk_drag_get_protocol (xevent->xproperty.window, &protocol))
1404 gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
1405 socket->plug_window,
1408 gdk_error_trap_pop ();
1410 else if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name ("_XEMBED_INFO"))
1412 unsigned long flags;
1414 if (xembed_get_info (socket->plug_window, NULL, &flags))
1416 gboolean was_mapped = socket->is_mapped;
1417 gboolean is_mapped = (flags & XEMBED_MAPPED) != 0;
1419 if (was_mapped != is_mapped)
1422 map_request (socket);
1425 gdk_error_trap_push ();
1426 gdk_window_show (socket->plug_window);
1428 gdk_error_trap_pop ();
1430 unmap_notify (socket);
1436 return_val = GDK_FILTER_REMOVE;
1439 case ReparentNotify:
1441 XReparentEvent *xre = &xevent->xreparent;
1443 if (!socket->plug_window && xre->parent == GDK_WINDOW_XWINDOW (widget->window))
1445 gtk_socket_add_window (socket, xre->window, FALSE);
1447 if (socket->plug_window)
1449 GTK_NOTE(PLUGSOCKET,
1450 g_message ("GtkSocket - window reparented"));
1453 return_val = GDK_FILTER_REMOVE;
1459 if (socket->plug_window &&
1460 xevent->xunmap.window == GDK_WINDOW_XWINDOW (socket->plug_window))
1462 GTK_NOTE(PLUGSOCKET,
1463 g_message ("GtkSocket - Unmap notify"));
1465 unmap_notify (socket);
1466 return_val = GDK_FILTER_REMOVE;