aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJochen Sprickerhof <suckless@jochen.sprickerhof.de>2024-02-01 06:16:04 +0300
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2024-02-03 16:09:35 +0300
commit1b61390375255529635d627397d3f759357d8613 (patch)
tree348e77c7d028702e5fe795422a63519c18e2d2c1
parenta6d484d8723d493bc09a5122128aaea729adaa80 (diff)
downloadst-fork-1b61390375255529635d627397d3f759357d8613.tar.gz
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 Source: https://lists.suckless.org/hackers/2001/17072.html
-rw-r--r--x.c82
1 files changed, 81 insertions, 1 deletions
diff --git a/x.c b/x.c
index af0dbe6..83ba5f3 100644
--- a/x.c
+++ b/x.c
@@ -69,6 +69,10 @@ void kscrolldown(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)
@@ -188,6 +192,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);
@@ -216,6 +223,8 @@ static void (*handler[LASTEvent])(XEvent *) = {
*/
[PropertyNotify] = propnotify,
[SelectionRequest] = selrequest,
+ [CreateNotify] = createnotify,
+ [DestroyNotify] = destroynotify,
};
/* Globals */
@@ -223,6 +232,7 @@ static DC dc;
static XWindow xw;
static XSelection xsel;
static TermWindow win;
+static Window embed;
/* Font Ring Cache */
enum {
@@ -750,6 +760,55 @@ cresize(int width, int height)
}
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)
{
win.tw = col * win.cw;
@@ -1170,7 +1229,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))))
@@ -1720,6 +1780,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;
}
@@ -1772,6 +1837,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;
@@ -1910,9 +1982,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);
}