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/.
30 #include "gdk/gdkkeysyms.h"
32 #include "gtkmarshalers.h"
33 #include "gtkwindow.h"
35 #include "gtkprivate.h"
36 #include "gtksocket.h"
43 typedef struct _GtkSocketPrivate GtkSocketPrivate;
45 struct _GtkSocketPrivate
50 /* Forward declararations */
52 static void gtk_socket_class_init (GtkSocketClass *klass);
53 static void gtk_socket_init (GtkSocket *socket);
54 static void gtk_socket_finalize (GObject *object);
55 static void gtk_socket_notify (GObject *object,
57 static void gtk_socket_realize (GtkWidget *widget);
58 static void gtk_socket_unrealize (GtkWidget *widget);
59 static void gtk_socket_size_request (GtkWidget *widget,
60 GtkRequisition *requisition);
61 static void gtk_socket_size_allocate (GtkWidget *widget,
62 GtkAllocation *allocation);
63 static void gtk_socket_hierarchy_changed (GtkWidget *widget,
64 GtkWidget *old_toplevel);
65 static void gtk_socket_grab_notify (GtkWidget *widget,
66 gboolean was_grabbed);
67 static gboolean gtk_socket_key_press_event (GtkWidget *widget,
69 static void gtk_socket_claim_focus (GtkSocket *socket,
71 static void gtk_socket_send_configure_event (GtkSocket *socket);
72 static gboolean gtk_socket_focus (GtkWidget *widget,
73 GtkDirectionType direction);
74 static void gtk_socket_remove (GtkContainer *container,
76 static void gtk_socket_forall (GtkContainer *container,
77 gboolean include_internals,
79 gpointer callback_data);
82 static void gtk_socket_add_window (GtkSocket *socket,
84 gboolean need_reparent);
85 static GdkFilterReturn gtk_socket_filter_func (GdkXEvent *gdk_xevent,
89 static void send_xembed_message (GtkSocket *socket,
95 static gboolean xembed_get_info (GdkWindow *gdk_window,
96 unsigned long *version,
97 unsigned long *flags);
100 #define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
110 static guint socket_signals[LAST_SIGNAL] = { 0 };
112 static GtkWidgetClass *parent_class = NULL;
115 gtk_socket_get_private (GtkSocket *socket)
117 GtkSocketPrivate *private;
118 static GQuark private_quark = 0;
121 private_quark = g_quark_from_static_string ("gtk-socket-private");
123 private = g_object_get_qdata (G_OBJECT (socket), private_quark);
127 private = g_new0 (GtkSocketPrivate, 1);
128 private->resize_count = 0;
130 g_object_set_qdata_full (G_OBJECT (socket), private_quark,
131 private, (GDestroyNotify) g_free);
138 gtk_socket_get_type (void)
140 static GType socket_type = 0;
144 static const GTypeInfo socket_info =
146 sizeof (GtkSocketClass),
147 NULL, /* base_init */
148 NULL, /* base_finalize */
149 (GClassInitFunc) gtk_socket_class_init,
150 NULL, /* class_finalize */
151 NULL, /* class_data */
153 16, /* n_preallocs */
154 (GInstanceInitFunc) gtk_socket_init,
157 socket_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkSocket",
165 gtk_socket_finalize (GObject *object)
167 GtkSocket *socket = GTK_SOCKET (object);
169 g_object_unref (socket->accel_group);
170 socket->accel_group = NULL;
172 G_OBJECT_CLASS (parent_class)->finalize (object);
176 gtk_socket_class_init (GtkSocketClass *class)
178 GtkWidgetClass *widget_class;
179 GtkContainerClass *container_class;
180 GObjectClass *gobject_class;
182 gobject_class = (GObjectClass *) class;
183 widget_class = (GtkWidgetClass*) class;
184 container_class = (GtkContainerClass*) class;
186 parent_class = g_type_class_peek_parent (class);
188 gobject_class->finalize = gtk_socket_finalize;
189 gobject_class->notify = gtk_socket_notify;
191 widget_class->realize = gtk_socket_realize;
192 widget_class->unrealize = gtk_socket_unrealize;
193 widget_class->size_request = gtk_socket_size_request;
194 widget_class->size_allocate = gtk_socket_size_allocate;
195 widget_class->hierarchy_changed = gtk_socket_hierarchy_changed;
196 widget_class->grab_notify = gtk_socket_grab_notify;
197 widget_class->key_press_event = gtk_socket_key_press_event;
198 widget_class->focus = gtk_socket_focus;
200 container_class->remove = gtk_socket_remove;
201 container_class->forall = gtk_socket_forall;
203 socket_signals[PLUG_ADDED] =
204 g_signal_new ("plug_added",
205 G_OBJECT_CLASS_TYPE (class),
207 G_STRUCT_OFFSET (GtkSocketClass, plug_added),
209 _gtk_marshal_VOID__VOID,
211 socket_signals[PLUG_REMOVED] =
212 g_signal_new ("plug_removed",
213 G_OBJECT_CLASS_TYPE (class),
215 G_STRUCT_OFFSET (GtkSocketClass, plug_removed),
216 _gtk_boolean_handled_accumulator, NULL,
217 _gtk_marshal_BOOLEAN__VOID,
222 gtk_socket_init (GtkSocket *socket)
224 socket->request_width = 0;
225 socket->request_height = 0;
226 socket->current_width = 0;
227 socket->current_height = 0;
229 socket->plug_window = NULL;
230 socket->plug_widget = NULL;
231 socket->focus_in = FALSE;
232 socket->have_size = FALSE;
233 socket->need_map = FALSE;
234 socket->active = FALSE;
236 socket->accel_group = gtk_accel_group_new ();
237 g_object_set_data (G_OBJECT (socket->accel_group), "gtk-socket", socket);
243 * Create a new empty #GtkSocket.
245 * Return value: the new #GtkSocket.
248 gtk_socket_new (void)
252 socket = g_object_new (GTK_TYPE_SOCKET, NULL);
254 return GTK_WIDGET (socket);
259 * @socket_: a #GtkSocket
260 * @wid: the window ID of an existing toplevel window.
262 * Reparents a pre-existing toplevel window into a #GtkSocket. This is
263 * meant to embed clients that do not know about embedding into a
264 * #GtkSocket, however doing so is inherently unreliable, and using
265 * this function is not recommended.
267 * The #GtkSocket must have already be added into a toplevel window
268 * before you can make this call.
271 gtk_socket_steal (GtkSocket *socket, GdkNativeWindow wid)
273 g_return_if_fail (GTK_IS_SOCKET (socket));
274 g_return_if_fail (GTK_WIDGET_ANCHORED (socket));
276 if (!GTK_WIDGET_REALIZED (socket))
277 gtk_widget_realize (GTK_WIDGET (socket));
279 gtk_socket_add_window (socket, wid, TRUE);
284 * @socket_: a #GtkSocket
285 * @window_id: the window ID of a client participating in the XEMBED protocol.
287 * Adds an XEMBED client, such as a #GtkPlug, to the #GtkSocket. The
288 * client may be in the same process or in a different process.
290 * To embed a #GtkPlug in a #GtkSocket, you can either create the
291 * #GtkPlug with <literal>gtk_plug_new (0)</literal>, call
292 * gtk_plug_get_id() to get the window ID of the plug, and then pass that to the
293 * gtk_socket_add_id(), or you can call gtk_socket_get_id() to get the
294 * window ID for the socket, and call gtk_plug_new() passing in that
297 * The #GtkSocket must have already be added into a toplevel window
298 * before you can make this call.
301 gtk_socket_add_id (GtkSocket *socket, GdkNativeWindow window_id)
303 g_return_if_fail (GTK_IS_SOCKET (socket));
304 g_return_if_fail (GTK_WIDGET_ANCHORED (socket));
306 if (!GTK_WIDGET_REALIZED (socket))
307 gtk_widget_realize (GTK_WIDGET (socket));
309 gtk_socket_add_window (socket, window_id, TRUE);
314 * @socket_: a #GtkSocket.
316 * Gets the window ID of a #GtkSocket widget, which can then
317 * be used to create a client embedded inside the socket, for
318 * instance with gtk_plug_new().
320 * The #GtkSocket must have already be added into a toplevel window
321 * before you can make this call.
323 * Return value: the window ID for the socket
326 gtk_socket_get_id (GtkSocket *socket)
328 g_return_val_if_fail (GTK_IS_SOCKET (socket), 0);
329 g_return_val_if_fail (GTK_WIDGET_ANCHORED (socket), 0);
331 if (!GTK_WIDGET_REALIZED (socket))
332 gtk_widget_realize (GTK_WIDGET (socket));
334 return GDK_WINDOW_XWINDOW (GTK_WIDGET (socket)->window);
338 gtk_socket_realize (GtkWidget *widget)
341 GdkWindowAttr attributes;
342 gint attributes_mask;
343 XWindowAttributes xattrs;
345 g_return_if_fail (GTK_IS_SOCKET (widget));
347 socket = GTK_SOCKET (widget);
348 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
350 attributes.window_type = GDK_WINDOW_CHILD;
351 attributes.x = widget->allocation.x;
352 attributes.y = widget->allocation.y;
353 attributes.width = widget->allocation.width;
354 attributes.height = widget->allocation.height;
355 attributes.wclass = GDK_INPUT_OUTPUT;
356 attributes.visual = gtk_widget_get_visual (widget);
357 attributes.colormap = gtk_widget_get_colormap (widget);
358 attributes.event_mask = GDK_FOCUS_CHANGE_MASK;
360 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
362 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
363 &attributes, attributes_mask);
364 gdk_window_set_user_data (widget->window, socket);
366 widget->style = gtk_style_attach (widget->style, widget->window);
367 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
369 XGetWindowAttributes (GDK_WINDOW_XDISPLAY (widget->window),
370 GDK_WINDOW_XWINDOW (widget->window),
373 XSelectInput (GDK_WINDOW_XDISPLAY (widget->window),
374 GDK_WINDOW_XWINDOW (widget->window),
375 xattrs.your_event_mask |
376 SubstructureNotifyMask | SubstructureRedirectMask);
378 gdk_window_add_filter (widget->window, gtk_socket_filter_func, widget);
380 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
382 /* We sync here so that we make sure that if the XID for
383 * our window is passed to another application, SubstructureRedirectMask
384 * will be set by the time the other app creates its window.
386 gdk_display_sync (gtk_widget_get_display (widget));
390 gtk_socket_end_embedding (GtkSocket *socket)
392 GtkSocketPrivate *private = gtk_socket_get_private (socket);
393 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
396 if (toplevel && GTK_IS_WINDOW (toplevel))
397 gtk_window_remove_embedded_xid (GTK_WINDOW (toplevel),
398 GDK_WINDOW_XWINDOW (socket->plug_window));
400 g_object_unref (socket->plug_window);
401 socket->plug_window = NULL;
402 private->resize_count = 0;
404 /* Remove from end to avoid indexes shifting. This is evil */
405 for (i = socket->accel_group->n_accels - 1; i >= 0; i--)
407 GtkAccelGroupEntry *accel_entry = &socket->accel_group->priv_accels[i];
408 gtk_accel_group_disconnect (socket->accel_group, accel_entry->closure);
413 gtk_socket_unrealize (GtkWidget *widget)
415 GtkSocket *socket = GTK_SOCKET (widget);
417 GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED);
419 if (socket->plug_widget)
421 _gtk_plug_remove_from_socket (GTK_PLUG (socket->plug_widget), socket);
423 else if (socket->plug_window)
425 gtk_socket_end_embedding (socket);
428 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
429 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
433 gtk_socket_size_request (GtkWidget *widget,
434 GtkRequisition *requisition)
436 GtkSocket *socket = GTK_SOCKET (widget);
438 if (socket->plug_widget)
440 gtk_widget_size_request (socket->plug_widget, requisition);
444 if (socket->is_mapped && !socket->have_size && socket->plug_window)
449 gdk_error_trap_push ();
451 socket->request_width = 1;
452 socket->request_height = 1;
454 if (XGetWMNormalHints (GDK_WINDOW_XDISPLAY (socket->plug_window),
455 GDK_WINDOW_XWINDOW (socket->plug_window),
458 if (hints.flags & PMinSize)
460 socket->request_width = hints.min_width;
461 socket->request_height = hints.min_height;
463 else if (hints.flags & PBaseSize)
465 socket->request_width = hints.base_width;
466 socket->request_height = hints.base_height;
469 socket->have_size = TRUE;
471 gdk_error_trap_pop ();
474 if (socket->is_mapped && socket->have_size)
476 requisition->width = MAX (socket->request_width, 1);
477 requisition->height = MAX (socket->request_height, 1);
481 requisition->width = 1;
482 requisition->height = 1;
488 gtk_socket_size_allocate (GtkWidget *widget,
489 GtkAllocation *allocation)
493 g_return_if_fail (GTK_IS_SOCKET (widget));
494 g_return_if_fail (allocation != NULL);
496 socket = GTK_SOCKET (widget);
498 widget->allocation = *allocation;
499 if (GTK_WIDGET_REALIZED (widget))
501 gdk_window_move_resize (widget->window,
502 allocation->x, allocation->y,
503 allocation->width, allocation->height);
505 if (socket->plug_widget)
507 GtkAllocation child_allocation;
509 child_allocation.x = 0;
510 child_allocation.y = 0;
511 child_allocation.width = allocation->width;
512 child_allocation.height = allocation->height;
514 gtk_widget_size_allocate (socket->plug_widget, &child_allocation);
516 else if (socket->plug_window)
518 GtkSocketPrivate *private = gtk_socket_get_private (socket);
520 gdk_error_trap_push ();
522 if (allocation->width != socket->current_width ||
523 allocation->height != socket->current_height)
525 gdk_window_move_resize (socket->plug_window,
527 allocation->width, allocation->height);
528 if (private->resize_count)
529 private->resize_count--;
532 g_message ("GtkSocket - allocated: %d %d",
533 allocation->width, allocation->height));
534 socket->current_width = allocation->width;
535 socket->current_height = allocation->height;
538 if (socket->need_map)
540 gdk_window_show (socket->plug_window);
541 socket->need_map = FALSE;
544 while (private->resize_count)
546 gtk_socket_send_configure_event (socket);
547 private->resize_count--;
549 g_message ("GtkSocket - sending synthetic configure: %d %d",
550 allocation->width, allocation->height));
553 gdk_display_sync (gtk_widget_get_display (widget));
554 gdk_error_trap_pop ();
562 GdkModifierType accel_mods;
566 activate_key (GtkAccelGroup *accel_group,
567 GObject *acceleratable,
569 GdkModifierType accel_mods,
570 GrabbedKey *grabbed_key)
573 GdkEvent *gdk_event = gtk_get_current_event ();
575 GtkSocket *socket = g_object_get_data (G_OBJECT (accel_group), "gtk-socket");
576 GdkScreen *screen = gdk_drawable_get_screen (socket->plug_window);
577 gboolean retval = FALSE;
579 if (gdk_event && gdk_event->type == GDK_KEY_PRESS && socket->plug_window)
581 xevent.xkey.type = KeyPress;
582 xevent.xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
583 xevent.xkey.root = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
584 xevent.xkey.subwindow = None;
585 xevent.xkey.time = gdk_event->key.time;
588 xevent.xkey.x_root = 0;
589 xevent.xkey.y_root = 0;
590 xevent.xkey.state = gdk_event->key.state;
591 xevent.xkey.keycode = gdk_event->key.hardware_keycode;
592 xevent.xkey.same_screen = True;
594 gdk_error_trap_push ();
595 XSendEvent (GDK_WINDOW_XDISPLAY (socket->plug_window),
596 GDK_WINDOW_XWINDOW (socket->plug_window),
597 False, KeyPressMask, &xevent);
598 gdk_display_sync (gdk_screen_get_display (screen));
599 gdk_error_trap_pop ();
605 gdk_event_free (gdk_event);
611 find_accel_key (GtkAccelKey *key,
615 GrabbedKey *grabbed_key = data;
617 return (key->accel_key == grabbed_key->accel_key &&
618 key->accel_mods == grabbed_key->accel_mods);
622 add_grabbed_key (GtkSocket *socket,
624 GdkModifierType modifiers)
627 GrabbedKey *grabbed_key;
629 grabbed_key = g_new (GrabbedKey, 1);
631 grabbed_key->accel_key = keyval;
632 grabbed_key->accel_mods = modifiers;
634 if (gtk_accel_group_find (socket->accel_group,
638 g_warning ("GtkSocket: request to add already present grabbed key %u,%#x\n",
640 g_free (grabbed_key);
644 closure = g_cclosure_new (G_CALLBACK (activate_key), grabbed_key, (GClosureNotify)g_free);
646 gtk_accel_group_connect (socket->accel_group, keyval, modifiers, GTK_ACCEL_LOCKED,
651 remove_grabbed_key (GtkSocket *socket,
653 GdkModifierType modifiers)
657 for (i = 0; i < socket->accel_group->n_accels; i++)
659 GtkAccelGroupEntry *accel_entry = &socket->accel_group->priv_accels[i];
660 if (accel_entry->key.accel_key == keyval &&
661 accel_entry->key.accel_mods == modifiers)
663 gtk_accel_group_disconnect (socket->accel_group,
664 accel_entry->closure);
669 g_warning ("GtkSocket: request to remove non-present grabbed key %u,%#x\n",
674 socket_update_focus_in (GtkSocket *socket)
676 gboolean focus_in = FALSE;
678 if (socket->plug_window)
680 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
681 if (GTK_WIDGET_TOPLEVEL (toplevel) &&
682 GTK_WINDOW (toplevel)->has_toplevel_focus &&
683 gtk_widget_is_focus (GTK_WIDGET (socket)))
687 if (focus_in != socket->focus_in)
689 socket->focus_in = focus_in;
693 send_xembed_message (socket, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT, 0, 0,
694 gtk_get_current_event_time ());
698 send_xembed_message (socket, XEMBED_FOCUS_OUT, 0, 0, 0,
699 gtk_get_current_event_time ());
706 socket_update_active (GtkSocket *socket)
708 gboolean active = FALSE;
710 if (socket->plug_window)
712 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
713 if (GTK_WIDGET_TOPLEVEL (toplevel) &&
714 GTK_WINDOW (toplevel)->is_active)
718 if (active != socket->active)
720 socket->active = active;
722 send_xembed_message (socket,
723 active ? XEMBED_WINDOW_ACTIVATE : XEMBED_WINDOW_DEACTIVATE,
725 gtk_get_current_event_time ());
730 gtk_socket_hierarchy_changed (GtkWidget *widget,
731 GtkWidget *old_toplevel)
733 GtkSocket *socket = GTK_SOCKET (widget);
734 GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
736 if (toplevel && !GTK_IS_WINDOW (toplevel))
739 if (toplevel != socket->toplevel)
741 if (socket->toplevel)
743 gtk_window_remove_accel_group (GTK_WINDOW (socket->toplevel), socket->accel_group);
744 g_signal_handlers_disconnect_by_func (socket->toplevel,
745 socket_update_focus_in,
747 g_signal_handlers_disconnect_by_func (socket->toplevel,
748 socket_update_active,
752 socket->toplevel = toplevel;
756 gtk_window_add_accel_group (GTK_WINDOW (socket->toplevel), socket->accel_group);
757 g_signal_connect_swapped (socket->toplevel, "notify::has-toplevel-focus",
758 G_CALLBACK (socket_update_focus_in), socket);
759 g_signal_connect_swapped (socket->toplevel, "notify::is-active",
760 G_CALLBACK (socket_update_active), socket);
763 socket_update_focus_in (socket);
764 socket_update_active (socket);
769 gtk_socket_grab_notify (GtkWidget *widget,
770 gboolean was_grabbed)
772 GtkSocket *socket = GTK_SOCKET (widget);
774 if (!socket->same_app)
775 send_xembed_message (GTK_SOCKET (widget),
776 was_grabbed ? XEMBED_MODALITY_OFF : XEMBED_MODALITY_ON,
777 0, 0, 0, gtk_get_current_event_time ());
781 gtk_socket_key_press_event (GtkWidget *widget,
784 GtkSocket *socket = GTK_SOCKET (widget);
786 if (GTK_WIDGET_HAS_FOCUS (socket) && socket->plug_window && !socket->plug_widget)
788 GdkScreen *screen = gdk_drawable_get_screen (socket->plug_window);
791 xevent.xkey.type = KeyPress;
792 xevent.xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
793 xevent.xkey.root = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
794 xevent.xkey.time = event->time;
795 /* FIXME, the following might cause problems for non-GTK apps */
798 xevent.xkey.x_root = 0;
799 xevent.xkey.y_root = 0;
800 xevent.xkey.state = event->state;
801 xevent.xkey.keycode = event->hardware_keycode;
802 xevent.xkey.same_screen = TRUE; /* FIXME ? */
804 gdk_error_trap_push ();
805 XSendEvent (GDK_WINDOW_XDISPLAY (socket->plug_window),
806 GDK_WINDOW_XWINDOW (socket->plug_window),
807 False, NoEventMask, &xevent);
808 gdk_display_sync (gtk_widget_get_display (widget));
809 gdk_error_trap_pop ();
818 gtk_socket_notify (GObject *object,
821 if (!strcmp (pspec->name, "is_focus"))
824 socket_update_focus_in (GTK_SOCKET (object));
828 gtk_socket_claim_focus (GtkSocket *socket,
832 socket->focus_in = TRUE; /* Otherwise, our notify handler will send FOCUS_IN */
834 /* Oh, the trickery... */
836 GTK_WIDGET_SET_FLAGS (socket, GTK_CAN_FOCUS);
837 gtk_widget_grab_focus (GTK_WIDGET (socket));
838 GTK_WIDGET_UNSET_FLAGS (socket, GTK_CAN_FOCUS);
842 gtk_socket_focus (GtkWidget *widget, GtkDirectionType direction)
847 g_return_val_if_fail (GTK_IS_SOCKET (widget), FALSE);
849 socket = GTK_SOCKET (widget);
851 if (socket->plug_widget)
852 return gtk_widget_child_focus (socket->plug_widget, direction);
854 if (!GTK_WIDGET_HAS_FOCUS (widget))
860 case GTK_DIR_TAB_BACKWARD:
861 detail = XEMBED_FOCUS_LAST;
865 case GTK_DIR_TAB_FORWARD:
866 detail = XEMBED_FOCUS_FIRST;
870 send_xembed_message (socket, XEMBED_FOCUS_IN, detail, 0, 0,
871 gtk_get_current_event_time ());
873 gtk_socket_claim_focus (socket, FALSE);
882 gtk_socket_remove (GtkContainer *container,
885 GtkSocket *socket = GTK_SOCKET (container);
887 g_return_if_fail (child == socket->plug_widget);
889 _gtk_plug_remove_from_socket (GTK_PLUG (socket->plug_widget), socket);
893 gtk_socket_forall (GtkContainer *container,
894 gboolean include_internals,
895 GtkCallback callback,
896 gpointer callback_data)
898 GtkSocket *socket = GTK_SOCKET (container);
900 if (socket->plug_widget)
901 (* callback) (socket->plug_widget, callback_data);
905 gtk_socket_send_configure_event (GtkSocket *socket)
910 g_return_if_fail (socket->plug_window != NULL);
912 event.xconfigure.type = ConfigureNotify;
914 event.xconfigure.event = GDK_WINDOW_XWINDOW (socket->plug_window);
915 event.xconfigure.window = GDK_WINDOW_XWINDOW (socket->plug_window);
917 /* The ICCCM says that synthetic events should have root relative
918 * coordinates. We still aren't really ICCCM compliant, since
919 * we don't send events when the real toplevel is moved.
921 gdk_error_trap_push ();
922 gdk_window_get_origin (socket->plug_window, &x, &y);
923 gdk_error_trap_pop ();
925 event.xconfigure.x = x;
926 event.xconfigure.y = y;
927 event.xconfigure.width = GTK_WIDGET(socket)->allocation.width;
928 event.xconfigure.height = GTK_WIDGET(socket)->allocation.height;
930 event.xconfigure.border_width = 0;
931 event.xconfigure.above = None;
932 event.xconfigure.override_redirect = False;
934 gdk_error_trap_push ();
935 XSendEvent (GDK_WINDOW_XDISPLAY (socket->plug_window),
936 GDK_WINDOW_XWINDOW (socket->plug_window),
937 False, NoEventMask, &event);
938 gdk_display_sync (gtk_widget_get_display (GTK_WIDGET (socket)));
939 gdk_error_trap_pop ();
943 gtk_socket_add_window (GtkSocket *socket,
945 gboolean need_reparent)
947 GtkWidget *widget = GTK_WIDGET (socket);
948 GdkDisplay *display = gtk_widget_get_display (widget);
949 gpointer user_data = NULL;
951 socket->plug_window = gdk_window_lookup_for_display (display, xid);
953 if (socket->plug_window)
955 g_object_ref (socket->plug_window);
956 gdk_window_get_user_data (socket->plug_window, &user_data);
959 if (user_data) /* A widget's window in this process */
961 GtkWidget *child_widget = user_data;
963 if (!GTK_IS_PLUG (child_widget))
965 g_warning (G_STRLOC "Can't add non-GtkPlug to GtkSocket");
966 socket->plug_window = NULL;
967 gdk_error_trap_pop ();
972 _gtk_plug_add_to_socket (GTK_PLUG (child_widget), socket);
974 else /* A foreign window */
977 GdkDragProtocol protocol;
978 unsigned long version;
981 gdk_error_trap_push ();
983 if (!socket->plug_window)
985 socket->plug_window = gdk_window_foreign_new_for_display (display, xid);
986 if (!socket->plug_window) /* was deleted before we could get it */
988 gdk_error_trap_pop ();
993 XSelectInput (GDK_DISPLAY_XDISPLAY (display),
994 GDK_WINDOW_XWINDOW (socket->plug_window),
995 StructureNotifyMask | PropertyChangeMask);
997 if (gdk_error_trap_pop ())
999 g_object_unref (socket->plug_window);
1000 socket->plug_window = NULL;
1004 /* OK, we now will reliably get destroy notification on socket->plug_window */
1006 gdk_error_trap_push ();
1010 gdk_window_hide (socket->plug_window); /* Shouldn't actually be necessary for XEMBED, but just in case */
1011 gdk_window_reparent (socket->plug_window, widget->window, 0, 0);
1014 socket->have_size = FALSE;
1016 socket->xembed_version = -1;
1017 if (xembed_get_info (socket->plug_window, &version, &flags))
1019 socket->xembed_version = version;
1020 socket->is_mapped = (flags & XEMBED_MAPPED) != 0;
1024 /* FIXME, we should probably actually check the state before we started */
1026 socket->is_mapped = TRUE;
1029 socket->need_map = socket->is_mapped;
1031 if (gdk_drag_get_protocol_for_display (display, xid, &protocol))
1032 gtk_drag_dest_set_proxy (GTK_WIDGET (socket), socket->plug_window,
1035 gdk_display_sync (display);
1036 gdk_error_trap_pop ();
1038 gdk_window_add_filter (socket->plug_window,
1039 gtk_socket_filter_func, socket);
1041 /* Add a pointer to the socket on our toplevel window */
1043 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
1044 if (toplevel && GTK_IS_WINDOW (toplevel))
1045 gtk_window_add_embedded_xid (GTK_WINDOW (toplevel), xid);
1047 send_xembed_message (socket, XEMBED_EMBEDDED_NOTIFY, 0, 0, 0,
1048 gtk_get_current_event_time ());
1049 socket_update_active (socket);
1050 socket_update_focus_in (socket);
1052 gtk_widget_queue_resize (GTK_WIDGET (socket));
1055 if (socket->plug_window)
1056 g_signal_emit (socket, socket_signals[PLUG_ADDED], 0);
1061 send_xembed_message (GtkSocket *socket,
1068 GTK_NOTE(PLUGSOCKET,
1069 g_message ("GtkSocket: Sending XEMBED message of type %ld", message));
1071 if (socket->plug_window)
1073 GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (socket));
1076 xevent.xclient.window = GDK_WINDOW_XWINDOW (socket->plug_window);
1077 xevent.xclient.type = ClientMessage;
1078 xevent.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED");
1079 xevent.xclient.format = 32;
1080 xevent.xclient.data.l[0] = time;
1081 xevent.xclient.data.l[1] = message;
1082 xevent.xclient.data.l[2] = detail;
1083 xevent.xclient.data.l[3] = data1;
1084 xevent.xclient.data.l[4] = data2;
1086 gdk_error_trap_push ();
1087 XSendEvent (GDK_DISPLAY_XDISPLAY (display),
1088 GDK_WINDOW_XWINDOW (socket->plug_window),
1089 False, NoEventMask, &xevent);
1090 gdk_display_sync (display);
1091 gdk_error_trap_pop ();
1096 xembed_get_info (GdkWindow *window,
1097 unsigned long *version,
1098 unsigned long *flags)
1100 GdkDisplay *display = gdk_drawable_get_display (window);
1101 Atom xembed_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO");
1104 unsigned long nitems, bytes_after;
1105 unsigned char *data;
1106 unsigned long *data_long;
1109 gdk_error_trap_push();
1110 status = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
1111 GDK_WINDOW_XWINDOW (window),
1114 xembed_info_atom, &type, &format,
1115 &nitems, &bytes_after, &data);
1116 gdk_error_trap_pop();
1118 if (status != Success)
1119 return FALSE; /* Window vanished? */
1121 if (type == None) /* No info property */
1124 if (type != xembed_info_atom)
1126 g_warning ("_XEMBED_INFO property has wrong type\n");
1132 g_warning ("_XEMBED_INFO too short\n");
1137 data_long = (unsigned long *)data;
1139 *version = data_long[0];
1141 *flags = data_long[1] & XEMBED_MAPPED;
1148 handle_xembed_message (GtkSocket *socket,
1155 GTK_NOTE (PLUGSOCKET,
1156 g_message ("GtkSocket: Message of type %ld received", message));
1160 case XEMBED_EMBEDDED_NOTIFY:
1161 case XEMBED_WINDOW_ACTIVATE:
1162 case XEMBED_WINDOW_DEACTIVATE:
1163 case XEMBED_MODALITY_ON:
1164 case XEMBED_MODALITY_OFF:
1165 case XEMBED_FOCUS_IN:
1166 case XEMBED_FOCUS_OUT:
1167 g_warning ("GtkSocket: Invalid _XEMBED message of type %ld received", message);
1170 case XEMBED_REQUEST_FOCUS:
1171 gtk_socket_claim_focus (socket, TRUE);
1174 case XEMBED_FOCUS_NEXT:
1175 case XEMBED_FOCUS_PREV:
1177 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
1180 gtk_widget_child_focus (toplevel,
1181 (message == XEMBED_FOCUS_NEXT ?
1182 GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD));
1187 case XEMBED_GTK_GRAB_KEY:
1188 add_grabbed_key (socket, data1, data2);
1190 case XEMBED_GTK_UNGRAB_KEY:
1191 remove_grabbed_key (socket, data1, data2);
1194 case XEMBED_GRAB_KEY:
1195 case XEMBED_UNGRAB_KEY:
1199 GTK_NOTE (PLUGSOCKET,
1200 g_message ("GtkSocket: Ignoring unknown _XEMBED message of type %ld", message));
1206 map_request (GtkSocket *socket)
1208 if (!socket->is_mapped)
1210 socket->is_mapped = TRUE;
1211 socket->need_map = TRUE;
1213 gtk_widget_queue_resize (GTK_WIDGET (socket));
1218 unmap_notify (GtkSocket *socket)
1220 if (socket->is_mapped)
1222 socket->is_mapped = FALSE;
1223 gtk_widget_queue_resize (GTK_WIDGET (socket));
1227 static GdkFilterReturn
1228 gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
1232 GdkDisplay *display;
1235 GdkFilterReturn return_val;
1237 socket = GTK_SOCKET (data);
1238 widget = GTK_WIDGET (socket);
1239 xevent = (XEvent *)gdk_xevent;
1240 display = gtk_widget_get_display (widget);
1242 return_val = GDK_FILTER_CONTINUE;
1244 if (socket->plug_widget)
1247 switch (xevent->type)
1250 if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED"))
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 GTK_NOTE(PLUGSOCKET,
1275 g_message ("GtkSocket - window created"));
1279 return_val = GDK_FILTER_REMOVE;
1284 case ConfigureRequest:
1286 XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
1288 if (!socket->plug_window)
1289 gtk_socket_add_window (socket, xcre->window, FALSE);
1291 if (socket->plug_window)
1293 GtkSocketPrivate *private = gtk_socket_get_private (socket);
1295 if (xcre->value_mask & (CWWidth | CWHeight))
1297 GTK_NOTE(PLUGSOCKET,
1298 g_message ("GtkSocket - configure request: %d %d",
1299 socket->request_width,
1300 socket->request_height));
1302 private->resize_count++;
1303 gtk_widget_queue_resize (widget);
1305 else if (xcre->value_mask & (CWX | CWY))
1307 gtk_socket_send_configure_event (socket);
1309 /* Ignore stacking requests. */
1311 return_val = GDK_FILTER_REMOVE;
1318 XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
1320 /* Note that we get destroy notifies both from SubstructureNotify on
1321 * our window and StructureNotify on socket->plug_window
1323 if (socket->plug_window && (xdwe->window == GDK_WINDOW_XWINDOW (socket->plug_window)))
1327 GTK_NOTE(PLUGSOCKET,
1328 g_message ("GtkSocket - destroy notify"));
1330 gdk_window_destroy_notify (socket->plug_window);
1331 gtk_socket_end_embedding (socket);
1333 g_object_ref (widget);
1334 g_signal_emit (widget, socket_signals[PLUG_REMOVED], 0, &result);
1336 gtk_widget_destroy (widget);
1337 g_object_unref (widget);
1339 return_val = GDK_FILTER_REMOVE;
1345 if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
1347 gtk_socket_claim_focus (socket, TRUE);
1349 return_val = GDK_FILTER_REMOVE;
1352 return_val = GDK_FILTER_REMOVE;
1355 if (!socket->plug_window)
1356 gtk_socket_add_window (socket, xevent->xmaprequest.window, FALSE);
1358 if (socket->plug_window)
1360 GTK_NOTE(PLUGSOCKET,
1361 g_message ("GtkSocket - Map Request"));
1363 map_request (socket);
1364 return_val = GDK_FILTER_REMOVE;
1367 case PropertyNotify:
1368 if (socket->plug_window &&
1369 xevent->xproperty.window == GDK_WINDOW_XWINDOW (socket->plug_window))
1371 GdkDragProtocol protocol;
1373 if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_NORMAL_HINTS"))
1375 socket->have_size = FALSE;
1376 gtk_widget_queue_resize (widget);
1378 else if ((xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndAware")) ||
1379 (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO")))
1381 gdk_error_trap_push ();
1382 if (gdk_drag_get_protocol_for_display (display,
1383 xevent->xproperty.window,
1385 gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
1386 socket->plug_window,
1389 gdk_display_sync (display);
1390 gdk_error_trap_pop ();
1392 else if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO"))
1394 unsigned long flags;
1396 if (xembed_get_info (socket->plug_window, NULL, &flags))
1398 gboolean was_mapped = socket->is_mapped;
1399 gboolean is_mapped = (flags & XEMBED_MAPPED) != 0;
1401 if (was_mapped != is_mapped)
1404 map_request (socket);
1407 gdk_error_trap_push ();
1408 gdk_window_show (socket->plug_window);
1410 gdk_error_trap_pop ();
1412 unmap_notify (socket);
1418 return_val = GDK_FILTER_REMOVE;
1421 case ReparentNotify:
1423 XReparentEvent *xre = &xevent->xreparent;
1425 if (!socket->plug_window && xre->parent == GDK_WINDOW_XWINDOW (widget->window))
1427 gtk_socket_add_window (socket, xre->window, FALSE);
1429 if (socket->plug_window)
1431 GTK_NOTE(PLUGSOCKET,
1432 g_message ("GtkSocket - window reparented"));
1435 return_val = GDK_FILTER_REMOVE;
1441 if (socket->plug_window &&
1442 xevent->xunmap.window == GDK_WINDOW_XWINDOW (socket->plug_window))
1444 GTK_NOTE(PLUGSOCKET,
1445 g_message ("GtkSocket - Unmap notify"));
1447 unmap_notify (socket);
1448 return_val = GDK_FILTER_REMOVE;