diff --git a/README.md b/README.md index d7ba6f8..c41a87b 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ Refer to [https://st.suckless.org/](https://st.suckless.org/) for details on the ### Changelog: +2020-01-07 - Added st embedder patch + 2019-10-16 - Introduced [flexipatch-finalizer](https://github.com/bakkeby/flexipatch-finalizer) 2019-09-17 - Added relativeborder, fix-keyboard-input, iso14755, visualbell, right-click-to-plumb, boxdraw and keyboard-select patches @@ -81,6 +83,10 @@ Refer to [https://st.suckless.org/](https://st.suckless.org/) for details on the - [scrollback](https://st.suckless.org/patches/scrollback/) - allows you scroll back through terminal output using keyboard shortcuts or mousewheel + - st-embedder + - this patch allows clients to embed into the st window and can be useful if you tend to start X applications from the terminal + - the behavior is similar to Plan 9 where applications can take over windows + - [spoiler](https://st.suckless.org/patches/spoiler/) - use inverted defaultbg/fg for selection when bg/fg are the same diff --git a/patch/st_embedder_x.c b/patch/st_embedder_x.c new file mode 100644 index 0000000..c73c389 --- /dev/null +++ b/patch/st_embedder_x.c @@ -0,0 +1,50 @@ +static Window embed; + +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); +} diff --git a/patch/st_embedder_x.h b/patch/st_embedder_x.h new file mode 100644 index 0000000..6910fb9 --- /dev/null +++ b/patch/st_embedder_x.h @@ -0,0 +1,7 @@ +#define XEMBED_EMBEDDED_NOTIFY 0 +#define XEMBED_WINDOW_ACTIVATE 1 +#define XEMBED_FOCUS_CURRENT 0 + +static void createnotify(XEvent *e); +static void destroynotify(XEvent *e); +static void sendxembed(long msg, long detail, long d1, long d2); \ No newline at end of file diff --git a/patch/x_include.c b/patch/x_include.c index ac6383f..af9596d 100644 --- a/patch/x_include.c +++ b/patch/x_include.c @@ -17,6 +17,9 @@ #if RIGHTCLICKTOPLUMB_PATCH #include "rightclicktoplumb_x.c" #endif +#if ST_EMBEDDER_PATCH +#include "st_embedder_x.c" +#endif #if VISUALBELL_2_PATCH || VISUALBELL_3_PATCH #include "visualbell.c" #endif diff --git a/patch/x_include.h b/patch/x_include.h index 560f4f3..29852fe 100644 --- a/patch/x_include.h +++ b/patch/x_include.h @@ -14,6 +14,9 @@ #if RIGHTCLICKTOPLUMB_PATCH #include "rightclicktoplumb_x.h" #endif +#if ST_EMBEDDER_PATCH +#include "st_embedder_x.h" +#endif #if VISUALBELL_2_PATCH || VISUALBELL_3_PATCH #include "visualbell.h" #endif diff --git a/patches.h b/patches.h index fffcddc..4338cab 100644 --- a/patches.h +++ b/patches.h @@ -136,6 +136,16 @@ */ #define SCROLLBACK_MOUSE_ALTSCREEN_PATCH 0 +/* This patch allows clients to embed into the st window and is useful if you tend to + * start X applications from the terminal. For example: + * + * $ surf -e $WINDOWID + * + * The behavior is similar to Plan 9 where applications can take over windows. + * URL TBC + */ +#define ST_EMBEDDER_PATCH 0 + /* Use inverted defaultbg/fg for selection when bg/fg are the same. * https://st.suckless.org/patches/spoiler/ */ diff --git a/x.c b/x.c index c2c80fb..a669bcb 100644 --- a/x.c +++ b/x.c @@ -227,6 +227,10 @@ static void (*handler[LASTEvent])(XEvent *) = { */ [PropertyNotify] = propnotify, [SelectionRequest] = selrequest, + #if ST_EMBEDDER_PATCH + [CreateNotify] = createnotify, + [DestroyNotify] = destroynotify, + #endif // ST_EMBEDDER_PATCH }; /* Globals */ @@ -1189,7 +1193,11 @@ xinit(int cols, int rows) | KeyReleaseMask #endif // FIXIME_PATCH | ExposureMask | VisibilityChangeMask | StructureNotifyMask - | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; + | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask + #if ST_EMBEDDER_PATCH + | SubstructureNotifyMask | SubstructureRedirectMask + #endif // ST_EMBEDDER_PATCH + ; xw.attrs.colormap = xw.cmap; #if !ALPHA_PATCH @@ -1889,6 +1897,13 @@ visibility(XEvent *ev) void unmap(XEvent *ev) { + #if ST_EMBEDDER_PATCH + if (embed == ev->xunmap.window) { + embed = 0; + XRaiseWindow(xw.dpy, xw.win); + XSetInputFocus(xw.dpy, xw.win, RevertToParent, CurrentTime); + } + #endif // ST_EMBEDDER_PATCH win.mode &= ~MODE_VISIBLE; } @@ -1960,6 +1975,15 @@ focus(XEvent *ev) { XFocusChangeEvent *e = &ev->xfocus; + #if ST_EMBEDDER_PATCH + 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); + } + #endif // ST_EMBEDDER_PATCH + if (e->mode == NotifyGrab) return; @@ -2108,9 +2132,21 @@ cmessage(XEvent *e) void resize(XEvent *e) { + #if ST_EMBEDDER_PATCH + XWindowChanges wc; + #endif // ST_EMBEDDER_PATCH + if (e->xconfigure.width == win.w && e->xconfigure.height == win.h) return; + #if ST_EMBEDDER_PATCH + if (embed) { + wc.width = e->xconfigure.width; + wc.height = e->xconfigure.height; + XConfigureWindow(xw.dpy, embed, CWWidth | CWHeight, &wc); + } + #endif // ST_EMBEDDER_PATCH + cresize(e->xconfigure.width, e->xconfigure.height); }