+
+static gboolean
+xembed_get_info (GdkWindow *window,
+ unsigned long *version,
+ unsigned long *flags)
+{
+ GdkDisplay *display = gdk_window_get_display (window);
+ Atom xembed_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO");
+ Atom type;
+ int format;
+ unsigned long nitems, bytes_after;
+ unsigned char *data;
+ unsigned long *data_long;
+ int status;
+
+ gdk_error_trap_push ();
+ status = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
+ GDK_WINDOW_XID (window),
+ xembed_info_atom,
+ 0, 2, False,
+ xembed_info_atom, &type, &format,
+ &nitems, &bytes_after, &data);
+ gdk_error_trap_pop_ignored ();
+
+ if (status != Success)
+ return FALSE; /* Window vanished? */
+
+ if (type == None) /* No info property */
+ return FALSE;
+
+ if (type != xembed_info_atom)
+ {
+ g_warning ("_XEMBED_INFO property has wrong type\n");
+ return FALSE;
+ }
+
+ if (nitems < 2)
+ {
+ g_warning ("_XEMBED_INFO too short\n");
+ XFree (data);
+ return FALSE;
+ }
+
+ data_long = (unsigned long *)data;
+ if (version)
+ *version = data_long[0];
+ if (flags)
+ *flags = data_long[1] & XEMBED_MAPPED;
+
+ XFree (data);
+ return TRUE;
+}
+
+static void
+handle_xembed_message (GtkSocket *socket,
+ XEmbedMessageType message,
+ glong detail,
+ glong data1,
+ glong data2,
+ guint32 time)
+{
+ GTK_NOTE (PLUGSOCKET,
+ g_message ("GtkSocket: %s received", _gtk_xembed_message_name (message)));
+
+ switch (message)
+ {
+ case XEMBED_EMBEDDED_NOTIFY:
+ case XEMBED_WINDOW_ACTIVATE:
+ case XEMBED_WINDOW_DEACTIVATE:
+ case XEMBED_MODALITY_ON:
+ case XEMBED_MODALITY_OFF:
+ case XEMBED_FOCUS_IN:
+ case XEMBED_FOCUS_OUT:
+ g_warning ("GtkSocket: Invalid _XEMBED message %s received", _gtk_xembed_message_name (message));
+ break;
+
+ case XEMBED_REQUEST_FOCUS:
+ gtk_socket_claim_focus (socket, TRUE);
+ break;
+
+ case XEMBED_FOCUS_NEXT:
+ case XEMBED_FOCUS_PREV:
+ gtk_socket_advance_toplevel_focus (socket,
+ (message == XEMBED_FOCUS_NEXT ?
+ GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD));
+ break;
+
+ case XEMBED_GTK_GRAB_KEY:
+ gtk_socket_add_grabbed_key (socket, data1, data2);
+ break;
+ case XEMBED_GTK_UNGRAB_KEY:
+ gtk_socket_remove_grabbed_key (socket, data1, data2);
+ break;
+
+ case XEMBED_GRAB_KEY:
+ case XEMBED_UNGRAB_KEY:
+ break;
+
+ default:
+ GTK_NOTE (PLUGSOCKET,
+ g_message ("GtkSocket: Ignoring unknown _XEMBED message of type %d", message));
+ break;
+ }
+}
+
+static GdkFilterReturn
+gtk_socket_filter_func (GdkXEvent *gdk_xevent,
+ GdkEvent *event,
+ gpointer data)
+{
+ GtkSocket *socket;
+ GtkWidget *widget;
+ GdkDisplay *display;
+ XEvent *xevent;
+ GtkSocketPrivate *private;
+
+ GdkFilterReturn return_val;
+
+ socket = GTK_SOCKET (data);
+ private = socket->priv;
+
+ return_val = GDK_FILTER_CONTINUE;
+
+ if (private->plug_widget)
+ return return_val;
+
+ widget = GTK_WIDGET (socket);
+ xevent = (XEvent *)gdk_xevent;
+ display = gtk_widget_get_display (widget);
+
+ switch (xevent->type)
+ {
+ case ClientMessage:
+ if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED"))
+ {
+ _gtk_xembed_push_message (xevent);
+ handle_xembed_message (socket,
+ xevent->xclient.data.l[1],
+ xevent->xclient.data.l[2],
+ xevent->xclient.data.l[3],
+ xevent->xclient.data.l[4],
+ xevent->xclient.data.l[0]);
+ _gtk_xembed_pop_message ();
+
+ return_val = GDK_FILTER_REMOVE;
+ }
+ break;
+
+ case CreateNotify:
+ {
+ XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
+
+ if (!private->plug_window)
+ {
+ gtk_socket_add_window (socket, xcwe->window, FALSE);
+
+ if (private->plug_window)
+ {
+ GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window created"));
+ }
+ }
+
+ return_val = GDK_FILTER_REMOVE;
+
+ break;
+ }
+
+ case ConfigureRequest:
+ {
+ XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
+
+ if (!private->plug_window)
+ gtk_socket_add_window (socket, xcre->window, FALSE);
+
+ if (private->plug_window)
+ {
+ if (xcre->value_mask & (CWWidth | CWHeight))
+ {
+ GTK_NOTE (PLUGSOCKET,
+ g_message ("GtkSocket - configure request: %d %d",
+ private->request_width,
+ private->request_height));
+
+ private->resize_count++;
+ gtk_widget_queue_resize (widget);
+ }
+ else if (xcre->value_mask & (CWX | CWY))
+ {
+ gtk_socket_send_configure_event (socket);
+ }
+ /* Ignore stacking requests. */
+
+ return_val = GDK_FILTER_REMOVE;
+ }
+ break;
+ }
+
+ case DestroyNotify:
+ {
+ XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
+
+ /* Note that we get destroy notifies both from SubstructureNotify on
+ * our window and StructureNotify on socket->plug_window
+ */
+ if (private->plug_window && (xdwe->window == GDK_WINDOW_XID (private->plug_window)))
+ {
+ gboolean result;
+
+ GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - destroy notify"));
+
+ gdk_window_destroy_notify (private->plug_window);
+ gtk_socket_end_embedding (socket);
+
+ g_object_ref (widget);
+ g_signal_emit_by_name (widget, "plug-removed", &result);
+ if (!result)
+ gtk_widget_destroy (widget);
+ g_object_unref (widget);
+
+ return_val = GDK_FILTER_REMOVE;
+ }
+ break;
+ }
+
+ case FocusIn:
+ if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
+ {
+ gtk_socket_claim_focus (socket, TRUE);
+ }
+ return_val = GDK_FILTER_REMOVE;
+ break;
+ case FocusOut:
+ return_val = GDK_FILTER_REMOVE;
+ break;
+ case MapRequest:
+ if (!private->plug_window)
+ {
+ gtk_socket_add_window (socket, xevent->xmaprequest.window, FALSE);
+ }
+
+ if (private->plug_window)
+ {
+ GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Map Request"));
+
+ gtk_socket_handle_map_request (socket);
+ return_val = GDK_FILTER_REMOVE;
+ }
+ break;
+ case PropertyNotify:
+ if (private->plug_window &&
+ xevent->xproperty.window == GDK_WINDOW_XID (private->plug_window))
+ {
+ GdkDragProtocol protocol;
+
+ if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_NORMAL_HINTS"))
+ {
+ GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - received PropertyNotify for plug's WM_NORMAL_HINTS"));
+ private->have_size = FALSE;
+ gtk_widget_queue_resize (widget);
+ return_val = GDK_FILTER_REMOVE;
+ }
+ else if ((xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndAware")) ||
+ (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO")))
+ {
+ gdk_error_trap_push ();
+ protocol = gdk_window_get_drag_protocol (private->plug_window, NULL);
+ if (protocol)
+ gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
+ private->plug_window,
+ protocol, TRUE);
+
+ gdk_error_trap_pop_ignored ();
+ return_val = GDK_FILTER_REMOVE;
+ }
+ else if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO"))
+ {
+ unsigned long flags;
+
+ if (xembed_get_info (private->plug_window, NULL, &flags))
+ {
+ gboolean was_mapped = private->is_mapped;
+ gboolean is_mapped = (flags & XEMBED_MAPPED) != 0;
+
+ if (was_mapped != is_mapped)
+ {
+ if (is_mapped)
+ gtk_socket_handle_map_request (socket);
+ else
+ {
+ gdk_error_trap_push ();
+ gdk_window_show (private->plug_window);
+ gdk_error_trap_pop_ignored ();
+
+ gtk_socket_unmap_notify (socket);
+ }
+ }
+ }
+ return_val = GDK_FILTER_REMOVE;
+ }
+ }
+ break;
+ case ReparentNotify:
+ {
+ GdkWindow *window;
+ XReparentEvent *xre = &xevent->xreparent;
+
+ window = gtk_widget_get_window (widget);
+
+ GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - ReparentNotify received"));
+ if (!private->plug_window &&
+ xre->parent == GDK_WINDOW_XID (window))
+ {
+ gtk_socket_add_window (socket, xre->window, FALSE);
+
+ if (private->plug_window)
+ {
+ GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window reparented"));
+ }
+
+ return_val = GDK_FILTER_REMOVE;
+ }
+ else
+ {
+ if (private->plug_window &&
+ xre->window == GDK_WINDOW_XID (private->plug_window) &&
+ xre->parent != GDK_WINDOW_XID (window))
+ {
+ gboolean result;
+
+ gtk_socket_end_embedding (socket);
+
+ g_object_ref (widget);
+ g_signal_emit_by_name (widget, "plug-removed", &result);
+ if (!result)
+ gtk_widget_destroy (widget);
+ g_object_unref (widget);
+
+ return_val = GDK_FILTER_REMOVE;
+ }
+ }
+
+ break;
+ }
+ case UnmapNotify:
+ if (private->plug_window &&
+ xevent->xunmap.window == GDK_WINDOW_XID (private->plug_window))
+ {
+ GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Unmap notify"));
+
+ gtk_socket_unmap_notify (socket);
+ return_val = GDK_FILTER_REMOVE;
+ }
+ break;
+
+ }
+
+ return return_val;
+}