diff --git a/README.md b/README.md index 64de0a3..67f028c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Refer to [https://dwm.suckless.org/](https://st.suckless.org/) for details on th ### Changelog: -2019-09-16 - Added alpha, anysize, bold-is-not-bright, clipboard, copyurl and disable-fonts patches +2019-09-16 - Added alpha, anysize, bold-is-not-bright, clipboard, copyurl, disable-fonts, fixime, hidecursor, newterm and open-copied-url patches ### Patches included: @@ -34,4 +34,17 @@ Refer to [https://dwm.suckless.org/](https://st.suckless.org/) for details on th - multiple invocations cycle through the available URLs - [disable-fonts](https://st.suckless.org/patches/disable_bold_italic_fonts/) - - this patch adds the option of disabling bold/italic/roman fonts globally \ No newline at end of file + - this patch adds the option of disabling bold/italic/roman fonts globally + + - [fixime](https://st.suckless.org/patches/fix_ime/) + - adds better Input Method Editor (IME) support + + - [hidecursor](https://st.suckless.org/patches/hidecursor/) + - hides the X cursor whenever a key is pressed and show it back when the mouse is moved in the terminal window + + - [newterm](https://st.suckless.org/patches/newterm/) + - allows you to spawn a new st terminal using Ctrl-Shift-Return + - it will have the same CWD (current working directory) as the original st instance + + - [open-copied-url](https://st.suckless.org/patches/open_copied_url/) + - open contents of the clipboard in a user-defined browser \ No newline at end of file diff --git a/config.def.h b/config.def.h index 8d38275..2b33860 100644 --- a/config.def.h +++ b/config.def.h @@ -198,6 +198,12 @@ static Shortcut shortcuts[] = { #if COPYURL_PATCH || COPYURL_HIGHLIGHT_SELECTED_URLS_PATCH { MODKEY, XK_l, copyurl, {.i = 0} }, #endif // COPYURL_PATCH + #if OPENCOPIED_PATCH + { MODKEY, XK_o, opencopied, {.v = "xdg-open"} }, + #endif // OPENCOPIED_PATCH + #if NEWTERM_PATCH + { TERMMOD, XK_Return, newterm, {.i = 0} }, + #endif // NEWTERM_PATCH }; /* diff --git a/patch/fixime.c b/patch/fixime.c new file mode 100644 index 0000000..43ee06f --- /dev/null +++ b/patch/fixime.c @@ -0,0 +1,49 @@ +void +ximopen(Display *dpy) +{ + XIMCallback destroy = { .client_data = NULL, .callback = ximdestroy }; + + if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { + XSetLocaleModifiers("@im=local"); + if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { + XSetLocaleModifiers("@im="); + if ((xw.xim = XOpenIM(xw.dpy, + NULL, NULL, NULL)) == NULL) { + die("XOpenIM failed. Could not open input" + " device.\n"); + } + } + } + if (XSetIMValues(xw.xim, XNDestroyCallback, &destroy, NULL) != NULL) + die("XSetIMValues failed. Could not set input method value.\n"); + xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, xw.win, XNFocusWindow, xw.win, NULL); + if (xw.xic == NULL) + die("XCreateIC failed. Could not obtain input method.\n"); +} + +void +ximinstantiate(Display *dpy, XPointer client, XPointer call) +{ + ximopen(dpy); + XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); +} + +void +ximdestroy(XIM xim, XPointer client, XPointer call) +{ + xw.xim = NULL; + XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); +} + +void +xximspot(int x, int y) +{ + XPoint spot = { borderpx + x * win.cw, borderpx + (y + 1) * win.ch }; + XVaNestedList attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL); + + XSetICValues(xw.xic, XNPreeditAttributes, attr, NULL); + XFree(attr); +} \ No newline at end of file diff --git a/patch/fixime.h b/patch/fixime.h new file mode 100644 index 0000000..959e178 --- /dev/null +++ b/patch/fixime.h @@ -0,0 +1,4 @@ +static void ximopen(Display *); +static void ximinstantiate(Display *, XPointer, XPointer); +static void ximdestroy(XIM, XPointer, XPointer); +void xximspot(int, int); \ No newline at end of file diff --git a/patch/include.h b/patch/include.h deleted file mode 100644 index 6fe70bb..0000000 --- a/patch/include.h +++ /dev/null @@ -1,5 +0,0 @@ -/* Patches */ - -#if COPYURL_PATCH || COPYURL_HIGHLIGHT_SELECTED_URLS_PATCH -#include "copyurl.h" -#endif \ No newline at end of file diff --git a/patch/newterm.c b/patch/newterm.c new file mode 100644 index 0000000..7e3ab28 --- /dev/null +++ b/patch/newterm.c @@ -0,0 +1,20 @@ +void +newterm(const Arg* a) +{ + int res; + switch (fork()) { + case -1: + die("fork failed: %s\n", strerror(errno)); + break; + case 0: + res = chdir(getcwd_by_pid(pid)); + execlp("st", "./st", NULL); + break; + } +} + +static char *getcwd_by_pid(pid_t pid) { + char buf[32]; + snprintf(buf, sizeof buf, "/proc/%d/cwd", pid); + return realpath(buf, NULL); +} \ No newline at end of file diff --git a/patch/newterm.h b/patch/newterm.h new file mode 100644 index 0000000..ea7292c --- /dev/null +++ b/patch/newterm.h @@ -0,0 +1,2 @@ +void newterm(const Arg *); +static char *getcwd_by_pid(pid_t pid); \ No newline at end of file diff --git a/patch/opencopied.c b/patch/opencopied.c new file mode 100644 index 0000000..9b07c58 --- /dev/null +++ b/patch/opencopied.c @@ -0,0 +1,19 @@ +void +opencopied(const Arg *arg) +{ + int res; + size_t const max_cmd = 2048; + char * const clip = xsel.clipboard; + if (!clip) { + fprintf(stderr, "Warning: nothing copied to clipboard\n"); + return; + } + + /* account for space/quote (3) and \0 (1) and & (1) */ + /* e.g.: xdg-open "https://st.suckless.org"& */ + size_t const cmd_size = max_cmd + strlen(clip) + 5; + char cmd[cmd_size]; + + snprintf(cmd, cmd_size, "%s \"%s\"&", (char *)arg->v, clip); + res = system(cmd); +} \ No newline at end of file diff --git a/patch/opencopied.h b/patch/opencopied.h new file mode 100644 index 0000000..3734ac7 --- /dev/null +++ b/patch/opencopied.h @@ -0,0 +1 @@ +void opencopied(const Arg *); \ No newline at end of file diff --git a/patch/include.c b/patch/st_include.c similarity index 64% rename from patch/include.c rename to patch/st_include.c index 31b3cd0..38b4ba0 100644 --- a/patch/include.c +++ b/patch/st_include.c @@ -2,4 +2,8 @@ #if COPYURL_PATCH || COPYURL_HIGHLIGHT_SELECTED_URLS_PATCH #include "copyurl.c" +#endif + +#if NEWTERM_PATCH +#include "newterm.c" #endif \ No newline at end of file diff --git a/patch/st_include.h b/patch/st_include.h new file mode 100644 index 0000000..9af27f9 --- /dev/null +++ b/patch/st_include.h @@ -0,0 +1,13 @@ +/* Patches */ + +#if COPYURL_PATCH || COPYURL_HIGHLIGHT_SELECTED_URLS_PATCH +#include "copyurl.h" +#endif + +#if FIXIME_PATCH +void xximspot(int, int); +#endif + +#if NEWTERM_PATCH +#include "newterm.h" +#endif \ No newline at end of file diff --git a/patch/x_include.c b/patch/x_include.c new file mode 100644 index 0000000..9b2e512 --- /dev/null +++ b/patch/x_include.c @@ -0,0 +1,9 @@ +/* Patches */ + +#if OPENCOPIED_PATCH +#include "opencopied.c" +#endif + +#if FIXIME_PATCH +#include "fixime.c" +#endif \ No newline at end of file diff --git a/patch/x_include.h b/patch/x_include.h new file mode 100644 index 0000000..f5dca48 --- /dev/null +++ b/patch/x_include.h @@ -0,0 +1,9 @@ +/* Patches */ + +#if OPENCOPIED_PATCH +#include "opencopied.h" +#endif + +#if FIXIME_PATCH +#include "fixime.h" +#endif \ No newline at end of file diff --git a/patches.h b/patches.h index 920d91f..b3b6722 100644 --- a/patches.h +++ b/patches.h @@ -46,14 +46,37 @@ /* This patch adds the option of disabling bold fonts globally. * https://st.suckless.org/patches/disable_bold_italic_fonts/ */ -#define DISABLE_BOLD_FONTS_PATCH 0 +#define DISABLE_BOLD_FONTS_PATCH 1 /* This patch adds the option of disabling italic fonts globally. * https://st.suckless.org/patches/disable_bold_italic_fonts/ */ -#define DISABLE_ITALIC_FONTS_PATCH 0 +#define DISABLE_ITALIC_FONTS_PATCH 1 /* This patch adds the option of disabling roman fonts globally. * https://st.suckless.org/patches/disable_bold_italic_fonts/ */ -#define DISABLE_ROMAN_FONTS_PATCH 0 +#define DISABLE_ROMAN_FONTS_PATCH 1 + +/* This patch adds better Input Method Editor (IME) support. + * https://st.suckless.org/patches/fix_ime/ + */ +#define FIXIME_PATCH 1 + +/* Hide the X cursor whenever a key is pressed and show it back when the mouse is moved in + * the terminal window. + * https://st.suckless.org/patches/hidecursor/ + */ +#define HIDECURSOR_PATCH 1 + +/* This patch allows you to spawn a new st terminal using Ctrl-Shift-Return. It will have the + * same CWD (current working directory) as the original st instance. + * https://st.suckless.org/patches/newterm/ + */ +#define NEWTERM_PATCH 1 + +/* Open contents of the clipboard in a user-defined browser. + * https://st.suckless.org/patches/open_copied_url/ + */ +#define OPENCOPIED_PATCH 1 + diff --git a/st.c b/st.c index 6daa853..94c6e01 100644 --- a/st.c +++ b/st.c @@ -232,7 +232,7 @@ static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; static Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; -#include "patch/include.h" +#include "patch/st_include.h" ssize_t xwrite(int fd, const char *s, size_t len) @@ -2596,6 +2596,9 @@ draw(void) term.ocx, term.ocy, term.line[term.ocy][term.ocx]); term.ocx = cx, term.ocy = term.c.y; xfinishdraw(); + #if FIXIME_PATCH + xximspot(term.ocx, term.ocy); + #endif // FIXIME_PATCH } void @@ -2605,4 +2608,4 @@ redraw(void) draw(); } -#include "patch/include.c" \ No newline at end of file +#include "patch/st_include.c" \ No newline at end of file diff --git a/x.c b/x.c index 4892ff2..a6ea20e 100644 --- a/x.c +++ b/x.c @@ -57,13 +57,12 @@ static void zoom(const Arg *); static void zoomabs(const Arg *); static void zoomreset(const Arg *); -#include "patch/include.h" +#include "patch/st_include.h" +#include "patch/x_include.h" /* config.h for applying patches and the configuration. */ #include "config.h" -//#include "patch/include.c" - /* XEMBED messages */ #define XEMBED_FOCUS_IN 4 #define XEMBED_FOCUS_OUT 5 @@ -103,6 +102,13 @@ typedef struct { Draw draw; Visual *vis; XSetWindowAttributes attrs; + #if HIDECURSOR_PATCH + /* Here, we use the term *pointer* to differentiate the cursor + * one sees when hovering the mouse over the terminal from, e.g., + * a green rectangle where text would be entered. */ + Cursor vpointer, bpointer; /* visible and hidden pointers */ + int pointerisvisible; + #endif // HIDECURSOR_PATCH int scr; int isfixed; /* is fixed geometry? */ #if ALPHA_PATCH @@ -253,6 +259,8 @@ static char *opt_title = NULL; static int oldbutton = 3; /* button event on startup: 3 = release */ +#include "patch/x_include.c" + void clipcopy(const Arg *dummy) { @@ -681,6 +689,15 @@ brelease(XEvent *e) void bmotion(XEvent *e) { + #if HIDECURSOR_PATCH + if (!xw.pointerisvisible) { + XDefineCursor(xw.dpy, xw.win, xw.vpointer); + xw.pointerisvisible = 1; + if (!IS_SET(MODE_MOUSEMANY)) + xsetpointermotion(0); + } + #endif // HIDECURSOR_PATCH + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { mousereport(e); return; @@ -1058,7 +1075,11 @@ void xinit(int cols, int rows) { XGCValues gcvalues; + #if HIDECURSOR_PATCH + Pixmap blankpm; + #else Cursor cursor; + #endif // HIDECURSOR_PATCH Window parent; pid_t thispid = getpid(); XColor xmousefg, xmousebg; @@ -1119,6 +1140,9 @@ xinit(int cols, int rows) xw.attrs.border_pixel = dc.col[defaultbg].pixel; xw.attrs.bit_gravity = NorthWestGravity; xw.attrs.event_mask = FocusChangeMask | KeyPressMask + #if FIXIME_PATCH + | KeyReleaseMask + #endif // FIXIME_PATCH | ExposureMask | VisibilityChangeMask | StructureNotifyMask | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; xw.attrs.colormap = xw.cmap; @@ -1158,6 +1182,9 @@ xinit(int cols, int rows) xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); /* input methods */ + #if FIXIME_PATCH + ximopen(xw.dpy); + #else if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { XSetLocaleModifiers("@im=local"); if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { @@ -1174,10 +1201,17 @@ xinit(int cols, int rows) XNFocusWindow, xw.win, NULL); if (xw.xic == NULL) die("XCreateIC failed. Could not obtain input method.\n"); + #endif // FIXIME_PATCH /* white cursor, black outline */ + #if HIDECURSOR_PATCH + xw.pointerisvisible = 1; + xw.vpointer = XCreateFontCursor(xw.dpy, mouseshape); + XDefineCursor(xw.dpy, xw.win, xw.vpointer); + #else cursor = XCreateFontCursor(xw.dpy, mouseshape); XDefineCursor(xw.dpy, xw.win, cursor); + #endif // HIDECURSOR_PATCH if (XParseColor(xw.dpy, xw.cmap, colorname[mousefg], &xmousefg) == 0) { xmousefg.red = 0xffff; @@ -1191,7 +1225,14 @@ xinit(int cols, int rows) xmousebg.blue = 0x0000; } + #if HIDECURSOR_PATCH + XRecolorCursor(xw.dpy, xw.vpointer, &xmousefg, &xmousebg); + blankpm = XCreateBitmapFromData(xw.dpy, xw.win, &(char){0}, 1, 1); + xw.bpointer = XCreatePixmapCursor(xw.dpy, blankpm, blankpm, + &xmousefg, &xmousebg, 0, 0); + #else XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg); + #endif // HIDECURSOR_PATCH xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); @@ -1733,6 +1774,10 @@ unmap(XEvent *ev) void xsetpointermotion(int set) { + #if HIDECURSOR_PATCH + if (!set && !xw.pointerisvisible) + return; + #endif // HIDECURSOR_PATCH MODBIT(xw.attrs.event_mask, set, PointerMotionMask); XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); } @@ -1851,6 +1896,14 @@ kpress(XEvent *ev) Status status; Shortcut *bp; + #if HIDECURSOR_PATCH + if (xw.pointerisvisible) { + XDefineCursor(xw.dpy, xw.win, xw.bpointer); + xsetpointermotion(1); + xw.pointerisvisible = 0; + } + #endif // HIDECURSOR_PATCH + if (IS_SET(MODE_KBDLOCK)) return;