Hi list,

I've implemented embedder support, i.e. the host part, for st. This allows clients to embed into the st window and is useful if you start X applications from the terminal. For example:

$ surf -e $WINDOWID

The behavior is similar to Plan 9 where applications can take over windows.. as far as this is possible in X ;).

The attached patch is against git master and I intent to put it into the wiki unless someone things it's worth for mainline.

Cheers Jochen
diff --git a/x.c b/x.c
index bc3ad5a..ebe4b6a 100644
--- a/x.c
+++ b/x.c
@@ -66,6 +66,10 @@ static void ttysend(const Arg *);
 /* XEMBED messages */
 #define XEMBED_FOCUS_IN  4
 #define XEMBED_FOCUS_OUT 5
+#define XEMBED_EMBEDDED_NOTIFY 0
+#define XEMBED_WINDOW_ACTIVATE 1
+#define XEMBED_FOCUS_CURRENT   0
+
 
 /* macros */
 #define IS_SET(flag)		((win.mode & (flag)) != 0)
@@ -179,6 +183,9 @@ static void mousesel(XEvent *, int);
 static void mousereport(XEvent *);
 static char *kmap(KeySym, uint);
 static int match(uint, uint);
+static void createnotify(XEvent *e);
+static void destroynotify(XEvent *e);
+static void sendxembed(long msg, long detail, long d1, long d2);
 
 static void run(void);
 static void usage(void);
@@ -207,6 +214,8 @@ static void (*handler[LASTEvent])(XEvent *) = {
  */
 	[PropertyNotify] = propnotify,
 	[SelectionRequest] = selrequest,
+	[CreateNotify] = createnotify,
+	[DestroyNotify] = destroynotify,
 };
 
 /* Globals */
@@ -214,6 +223,7 @@ static DC dc;
 static XWindow xw;
 static XSelection xsel;
 static TermWindow win;
+static Window embed;
 
 /* Font Ring Cache */
 enum {
@@ -706,6 +716,55 @@ cresize(int width, int height)
 	ttyresize(win.tw, win.th);
 }
 
+void
+createnotify(XEvent *e)
+{
+	XWindowChanges wc;
+
+	if (embed || e->xcreatewindow.override_redirect)
+		return;
+
+	embed = e->xcreatewindow.window;
+
+	XReparentWindow(xw.dpy, embed, xw.win, 0, 0);
+	XSelectInput(xw.dpy, embed, PropertyChangeMask | StructureNotifyMask | EnterWindowMask);
+
+	XMapWindow(xw.dpy, embed);
+	sendxembed(XEMBED_EMBEDDED_NOTIFY, 0, xw.win, 0);
+
+	wc.width = win.w;
+	wc.height = win.h;
+	XConfigureWindow(xw.dpy, embed, CWWidth | CWHeight, &wc);
+
+	XSetInputFocus(xw.dpy, embed, RevertToParent, CurrentTime);
+}
+
+void
+destroynotify(XEvent *e)
+{
+	visibility(e);
+	if (embed == e->xdestroywindow.window) {
+		focus(e);
+	}
+}
+
+void
+sendxembed(long msg, long detail, long d1, long d2)
+{
+	XEvent e = { 0 };
+
+	e.xclient.window = embed;
+	e.xclient.type = ClientMessage;
+	e.xclient.message_type = xw.xembed;
+	e.xclient.format = 32;
+	e.xclient.data.l[0] = CurrentTime;
+	e.xclient.data.l[1] = msg;
+	e.xclient.data.l[2] = detail;
+	e.xclient.data.l[3] = d1;
+	e.xclient.data.l[4] = d2;
+	XSendEvent(xw.dpy, embed, False, NoEventMask, &e);
+}
+
 void
 xresize(int col, int row)
 {
@@ -1097,7 +1156,8 @@ xinit(int cols, int rows)
 	xw.attrs.bit_gravity = NorthWestGravity;
 	xw.attrs.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask
 		| ExposureMask | VisibilityChangeMask | StructureNotifyMask
-		| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
+		| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask
+		| SubstructureNotifyMask | SubstructureRedirectMask;
 	xw.attrs.colormap = xw.cmap;
 
 	if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
@@ -1625,6 +1685,11 @@ visibility(XEvent *ev)
 void
 unmap(XEvent *ev)
 {
+	if (embed == ev->xunmap.window) {
+		embed = 0;
+		XRaiseWindow(xw.dpy, xw.win);
+		XSetInputFocus(xw.dpy, xw.win, RevertToParent, CurrentTime);
+	}
 	win.mode &= ~MODE_VISIBLE;
 }
 
@@ -1678,6 +1743,13 @@ focus(XEvent *ev)
 {
 	XFocusChangeEvent *e = &ev->xfocus;
 
+	if (embed && ev->type == FocusIn) {
+		XRaiseWindow(xw.dpy, embed);
+		XSetInputFocus(xw.dpy, embed, RevertToParent, CurrentTime);
+		sendxembed(XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT, 0, 0);
+		sendxembed(XEMBED_WINDOW_ACTIVATE, 0, 0, 0);
+	}
+
 	if (e->mode == NotifyGrab)
 		return;
 
@@ -1808,9 +1880,17 @@ cmessage(XEvent *e)
 void
 resize(XEvent *e)
 {
+	XWindowChanges wc;
+
 	if (e->xconfigure.width == win.w && e->xconfigure.height == win.h)
 		return;
 
+	if (embed) {
+		wc.width = e->xconfigure.width;
+		wc.height = e->xconfigure.height;
+		XConfigureWindow(xw.dpy, embed, CWWidth | CWHeight, &wc);
+	}
+
 	cresize(e->xconfigure.width, e->xconfigure.height);
 }

Attachment: signature.asc
Description: PGP signature

Reply via email to