Techniques

Handling errors

Implementors of the XEmbed protocol should handle the other party disappearing at any point. For this reason X errors must be trapped when performing any operation with a window not created by the application. This is done by using XSetErrorHandler(). A sample implementation of trapping errors in C looks like:

#include <X11/Xlib.h>

static int trapped_error_code = 0;
static int (*old_error_handler) (Display *, XErrorEvent *);

static int
error_handler(Display     *display,
	      XErrorEvent *error)
{
    trapped_error_code = error->error_code;
    return 0;
}

void
trap_errors(void)
{
    trapped_error_code = 0;
    old_error_handler = XSetErrorHandler(error_handler);
}

int
untrap_errors(void)
{
    XSetErrorHandler(old_error_handler);
    return trapped_error_code;
}

Forwarding X Events

An XEmbed embedder has to forward key-press and key-release events to its respective client.

Key events are forwarded by changing the event's window field to the window handle of the client and sending the modified message via XSendEvent() to the embedder, with no event mask and propagation turned off.

Note: XEmbed requires toolkits to handle key-events that come from a SendEvent request. That means, if somebody can access your X-Server, it's possible to fake keyboard input. Given that most toolkits accept sent key events today anyway and the X Server is typically protected through magic cookie authorization, this is not considered to be an issue. Applications with higher security requirements may choose not to use embedded components, though, and to filter out any events coming from XSendEvent().

Given that Window client is the client's window handle, here is a piece of code of an imaginary event-loop in C that does the forwarding.

#include <X11/Xlib.h>

void handle_event(
	Display* dpy, /* display */
	XEvent* ev /* event */
){
    if ( ev->type == KeyPress || ev->type == KeyRelease ) {
            ev->xkey.window = client;
	    trap_errors();
            XSendEvent( dpy, client, False, NoEventMask, ev );
	    XSync( dpy, False );
	    if (untrap_errors()) {
	       /* Handle failure */
	    }
	    
            return;
    }
    ... /* normal event handling */
}

Sending XEmbed messages

Given that Time x_time contains the timestamp from the event currently being processed. (CurrentTime is generally the best choice if no event is being processed), here is a valid implementation in C of sending an XEMBED message:

#include <X11/Xlib.h>

void send_xembed_message(
     Display* dpy, /* display */
     Window w, /* receiver */
     long message, /* message opcode */
     long detail  /* message detail */
     long data1  /* message data 1 */
     long data2  /* message data 2 */
){
    XEvent ev;
    memset(&ev, 0, sizeof(ev));
    ev.xclient.type = ClientMessage;
    ev.xclient.window = w;
    ev.xclient.message_type = XInternAtom( dpy, "_XEMBED", False );
    ev.xclient.format = 32;
    ev.xclient.data.l[0] = x_time;
    ev.xclient.data.l[1] = message;
    ev.xclient.data.l[2] = detail;
    ev.xclient.data.l[3] = data1;
    ev.xclient.data.l[4] = data2;
    trap_errors();
    XSendEvent(dpy, w, False, NoEventMask, &ev);
    XSync(dpy, False);
    if (untrap_errors()) {
	/* Handle failure */
    }
}