From fc821fb8430b1b535871098929efaba25fc085da Mon Sep 17 00:00:00 2001 From: Santiago Lo Coco Date: Sun, 28 Feb 2021 22:51:06 -0300 Subject: [PATCH] Added center, border and case insensitive --- Makefile | 2 +- config.def.h | 5 + config.def.h.orig | 25 + config.h | 5 + dmenu | Bin 43984 -> 43496 bytes dmenu.1 | 9 +- dmenu.1.orig | 197 +++++ dmenu.c | 52 +- dmenu.c.orig | 796 +++++++++++++++++++++ dmenu.o | Bin 32344 -> 33904 bytes drw.o | Bin 10624 -> 10616 bytes patches/dmenu-border-4.9.diff | 25 + patches/dmenu-caseinsensitive-5.0.diff | 53 ++ patches/dmenu-center-20200111-8cd37e1.diff | 120 ++++ stest | Bin 17744 -> 17080 bytes stest.o | Bin 5280 -> 5288 bytes util.o | Bin 2264 -> 2256 bytes 17 files changed, 1272 insertions(+), 17 deletions(-) create mode 100644 config.def.h.orig create mode 100644 dmenu.1.orig create mode 100644 dmenu.c.orig create mode 100644 patches/dmenu-border-4.9.diff create mode 100644 patches/dmenu-caseinsensitive-5.0.diff create mode 100644 patches/dmenu-center-20200111-8cd37e1.diff diff --git a/Makefile b/Makefile index a03a95c..fe864c3 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ stest: stest.o $(CC) -o $@ stest.o $(LDFLAGS) clean: - rm -f dmenu stest $(OBJ) dmenu-$(VERSION).tar.gz + rm -f dmenu stest $(OBJ) dmenu-$(VERSION).tar.gz config.h dist: clean mkdir -p dmenu-$(VERSION) diff --git a/config.def.h b/config.def.h index 1edb647..bd88a8b 100644 --- a/config.def.h +++ b/config.def.h @@ -2,6 +2,8 @@ /* Default settings; can be overriden by command line. */ static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */ +static int centered = 1; /* -c option; centers dmenu on screen */ +static int min_width = 500; /* minimum width when centered */ /* -fn option overrides fonts[0]; default X11 font or font set */ static const char *fonts[] = { "monospace:size=10" @@ -21,3 +23,6 @@ static unsigned int lines = 0; * for example: " /?\"&[]" */ static const char worddelimiters[] = " "; + +/* Size of the window border */ +static const unsigned int border_width = 5; diff --git a/config.def.h.orig b/config.def.h.orig new file mode 100644 index 0000000..d041d6f --- /dev/null +++ b/config.def.h.orig @@ -0,0 +1,25 @@ +/* See LICENSE file for copyright and license details. */ +/* Default settings; can be overriden by command line. */ + +static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */ +static int centered = 1; /* -c option; centers dmenu on screen */ +static int min_width = 500; /* minimum width when centered */ +/* -fn option overrides fonts[0]; default X11 font or font set */ +static const char *fonts[] = { + "monospace:size=10" +}; +static const char *prompt = NULL; /* -p option; prompt to the left of input field */ +static const char *colors[SchemeLast][2] = { + /* fg bg */ + [SchemeNorm] = { "#bbbbbb", "#222222" }, + [SchemeSel] = { "#eeeeee", "#005577" }, + [SchemeOut] = { "#000000", "#00ffff" }, +}; +/* -l option; if nonzero, dmenu uses vertical list with given number of lines */ +static unsigned int lines = 0; + +/* + * Characters not considered part of a word while deleting words + * for example: " /?\"&[]" + */ +static const char worddelimiters[] = " "; diff --git a/config.h b/config.h index 1edb647..bd88a8b 100644 --- a/config.h +++ b/config.h @@ -2,6 +2,8 @@ /* Default settings; can be overriden by command line. */ static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */ +static int centered = 1; /* -c option; centers dmenu on screen */ +static int min_width = 500; /* minimum width when centered */ /* -fn option overrides fonts[0]; default X11 font or font set */ static const char *fonts[] = { "monospace:size=10" @@ -21,3 +23,6 @@ static unsigned int lines = 0; * for example: " /?\"&[]" */ static const char worddelimiters[] = " "; + +/* Size of the window border */ +static const unsigned int border_width = 5; diff --git a/dmenu b/dmenu index 53cdd5f0b27ca30baed8695b28ce1a6d71f3a803..d216354c28b26a2cc06a64be4eff260db0c2019d 100755 GIT binary patch delta 15768 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 o^@u2^0R delta 15201 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 M)P#5%i8R3e4_e3U`v3p{ diff --git a/dmenu.1 b/dmenu.1 index 323f93c..2ab848a 100644 --- a/dmenu.1 +++ b/dmenu.1 @@ -3,7 +3,7 @@ dmenu \- dynamic menu .SH SYNOPSIS .B dmenu -.RB [ \-bfiv ] +.RB [ \-bfsv ] .RB [ \-l .IR lines ] .RB [ \-m @@ -40,12 +40,15 @@ which lists programs in the user's $PATH and runs the result in their $SHELL. .B \-b dmenu appears at the bottom of the screen. .TP +.B \-c +dmenu appears centered on the screen. +.TP .B \-f dmenu grabs the keyboard before reading stdin if not reading from a tty. This is faster, but will lock up X until stdin reaches end\-of\-file. .TP -.B \-i -dmenu matches menu items case insensitively. +.B \-s +dmenu matches menu items case sensitively. .TP .BI \-l " lines" dmenu lists items vertically, with the given number of lines. diff --git a/dmenu.1.orig b/dmenu.1.orig new file mode 100644 index 0000000..2ab848a --- /dev/null +++ b/dmenu.1.orig @@ -0,0 +1,197 @@ +.TH DMENU 1 dmenu\-VERSION +.SH NAME +dmenu \- dynamic menu +.SH SYNOPSIS +.B dmenu +.RB [ \-bfsv ] +.RB [ \-l +.IR lines ] +.RB [ \-m +.IR monitor ] +.RB [ \-p +.IR prompt ] +.RB [ \-fn +.IR font ] +.RB [ \-nb +.IR color ] +.RB [ \-nf +.IR color ] +.RB [ \-sb +.IR color ] +.RB [ \-sf +.IR color ] +.RB [ \-w +.IR windowid ] +.P +.BR dmenu_run " ..." +.SH DESCRIPTION +.B dmenu +is a dynamic menu for X, which reads a list of newline\-separated items from +stdin. When the user selects an item and presses Return, their choice is printed +to stdout and dmenu terminates. Entering text will narrow the items to those +matching the tokens in the input. +.P +.B dmenu_run +is a script used by +.IR dwm (1) +which lists programs in the user's $PATH and runs the result in their $SHELL. +.SH OPTIONS +.TP +.B \-b +dmenu appears at the bottom of the screen. +.TP +.B \-c +dmenu appears centered on the screen. +.TP +.B \-f +dmenu grabs the keyboard before reading stdin if not reading from a tty. This +is faster, but will lock up X until stdin reaches end\-of\-file. +.TP +.B \-s +dmenu matches menu items case sensitively. +.TP +.BI \-l " lines" +dmenu lists items vertically, with the given number of lines. +.TP +.BI \-m " monitor" +dmenu is displayed on the monitor number supplied. Monitor numbers are starting +from 0. +.TP +.BI \-p " prompt" +defines the prompt to be displayed to the left of the input field. +.TP +.BI \-fn " font" +defines the font or font set used. +.TP +.BI \-nb " color" +defines the normal background color. +.IR #RGB , +.IR #RRGGBB , +and X color names are supported. +.TP +.BI \-nf " color" +defines the normal foreground color. +.TP +.BI \-sb " color" +defines the selected background color. +.TP +.BI \-sf " color" +defines the selected foreground color. +.TP +.B \-v +prints version information to stdout, then exits. +.TP +.BI \-w " windowid" +embed into windowid. +.SH USAGE +dmenu is completely controlled by the keyboard. Items are selected using the +arrow keys, page up, page down, home, and end. +.TP +.B Tab +Copy the selected item to the input field. +.TP +.B Return +Confirm selection. Prints the selected item to stdout and exits, returning +success. +.TP +.B Ctrl-Return +Confirm selection. Prints the selected item to stdout and continues. +.TP +.B Shift\-Return +Confirm input. Prints the input text to stdout and exits, returning success. +.TP +.B Escape +Exit without selecting an item, returning failure. +.TP +.B Ctrl-Left +Move cursor to the start of the current word +.TP +.B Ctrl-Right +Move cursor to the end of the current word +.TP +.B C\-a +Home +.TP +.B C\-b +Left +.TP +.B C\-c +Escape +.TP +.B C\-d +Delete +.TP +.B C\-e +End +.TP +.B C\-f +Right +.TP +.B C\-g +Escape +.TP +.B C\-h +Backspace +.TP +.B C\-i +Tab +.TP +.B C\-j +Return +.TP +.B C\-J +Shift-Return +.TP +.B C\-k +Delete line right +.TP +.B C\-m +Return +.TP +.B C\-M +Shift-Return +.TP +.B C\-n +Down +.TP +.B C\-p +Up +.TP +.B C\-u +Delete line left +.TP +.B C\-w +Delete word left +.TP +.B C\-y +Paste from primary X selection +.TP +.B C\-Y +Paste from X clipboard +.TP +.B M\-b +Move cursor to the start of the current word +.TP +.B M\-f +Move cursor to the end of the current word +.TP +.B M\-g +Home +.TP +.B M\-G +End +.TP +.B M\-h +Up +.TP +.B M\-j +Page down +.TP +.B M\-k +Page up +.TP +.B M\-l +Down +.SH SEE ALSO +.IR dwm (1), +.IR stest (1) diff --git a/dmenu.c b/dmenu.c index 65f25ce..14ec562 100644 --- a/dmenu.c +++ b/dmenu.c @@ -55,8 +55,9 @@ static Clr *scheme[SchemeLast]; #include "config.h" -static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; -static char *(*fstrstr)(const char *, const char *) = strstr; +static char * cistrstr(const char *s, const char *sub); +static int (*fstrncmp)(const char *, const char *, size_t) = strncasecmp; +static char *(*fstrstr)(const char *, const char *) = cistrstr; static void appenditem(struct item *item, struct item **list, struct item **last) @@ -89,6 +90,15 @@ calcoffsets(void) break; } +static int +max_textw(void) +{ + int len = 0; + for (struct item *item = items; item && item->text; item++) + len = MAX(TEXTW(item->text), len); + return len; +} + static void cleanup(void) { @@ -611,6 +621,7 @@ setup(void) bh = drw->fonts->h + 2; lines = MAX(lines, 0); mh = (lines + 1) * bh; + promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; #ifdef XINERAMA i = 0; if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) { @@ -637,9 +648,15 @@ setup(void) if (INTERSECT(x, y, 1, 1, info[i])) break; - x = info[i].x_org; - y = info[i].y_org + (topbar ? 0 : info[i].height - mh); - mw = info[i].width; + if (centered) { + mw = MIN(MAX(max_textw() + promptw, min_width), info[i].width); + x = info[i].x_org + ((info[i].width - mw) / 2); + y = info[i].y_org + ((info[i].height - mh) / 2); + } else { + x = info[i].x_org; + y = info[i].y_org + (topbar ? 0 : info[i].height - mh); + mw = info[i].width; + } XFree(info); } else #endif @@ -647,11 +664,17 @@ setup(void) if (!XGetWindowAttributes(dpy, parentwin, &wa)) die("could not get embedding window attributes: 0x%lx", parentwin); - x = 0; - y = topbar ? 0 : wa.height - mh; - mw = wa.width; + + if (centered) { + mw = MIN(MAX(max_textw() + promptw, min_width), wa.width); + x = (wa.width - mw) / 2; + y = (wa.height - mh) / 2; + } else { + x = 0; + y = topbar ? 0 : wa.height - mh; + mw = wa.width; + } } - promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; inputw = MIN(inputw, mw/3); match(); @@ -659,9 +682,10 @@ setup(void) swa.override_redirect = True; swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; - win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0, + win = XCreateWindow(dpy, parentwin, x, y, mw, mh, border_width, CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); + XSetWindowBorder(dpy, win, scheme[SchemeSel][ColBg].pixel); XSetClassHint(dpy, win, &ch); @@ -709,9 +733,11 @@ main(int argc, char *argv[]) topbar = 0; else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ fast = 1; - else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ - fstrncmp = strncasecmp; - fstrstr = cistrstr; + else if (!strcmp(argv[i], "-c")) /* centers dmenu on screen */ + centered = 1; + else if (!strcmp(argv[i], "-s")) { /* case-sensitive item matching */ + fstrncmp = strncmp; + fstrstr = strstr; } else if (i + 1 == argc) usage(); /* these options take one argument */ diff --git a/dmenu.c.orig b/dmenu.c.orig new file mode 100644 index 0000000..0ef20d7 --- /dev/null +++ b/dmenu.c.orig @@ -0,0 +1,796 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#ifdef XINERAMA +#include +#endif +#include + +#include "drw.h" +#include "util.h" + +/* macros */ +#define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \ + * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org))) +#define LENGTH(X) (sizeof X / sizeof X[0]) +#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + +/* enums */ +enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ + +struct item { + char *text; + struct item *left, *right; + int out; +}; + +static char text[BUFSIZ] = ""; +static char *embed; +static int bh, mw, mh; +static int inputw = 0, promptw; +static int lrpad; /* sum of left and right padding */ +static size_t cursor; +static struct item *items = NULL; +static struct item *matches, *matchend; +static struct item *prev, *curr, *next, *sel; +static int mon = -1, screen; + +static Atom clip, utf8; +static Display *dpy; +static Window root, parentwin, win; +static XIC xic; + +static Drw *drw; +static Clr *scheme[SchemeLast]; + +#include "config.h" + +static char * cistrstr(const char *s, const char *sub); +static int (*fstrncmp)(const char *, const char *, size_t) = strncasecmp; +static char *(*fstrstr)(const char *, const char *) = cistrstr; + +static void +appenditem(struct item *item, struct item **list, struct item **last) +{ + if (*last) + (*last)->right = item; + else + *list = item; + + item->left = *last; + item->right = NULL; + *last = item; +} + +static void +calcoffsets(void) +{ + int i, n; + + if (lines > 0) + n = lines * bh; + else + n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">")); + /* calculate which items will begin the next page and previous page */ + for (i = 0, next = curr; next; next = next->right) + if ((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n) + break; + for (i = 0, prev = curr; prev && prev->left; prev = prev->left) + if ((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n) + break; +} + +static int +max_textw(void) +{ + int len = 0; + for (struct item *item = items; item && item->text; item++) + len = MAX(TEXTW(item->text), len); + return len; +} + +static void +cleanup(void) +{ + size_t i; + + XUngrabKey(dpy, AnyKey, AnyModifier, root); + for (i = 0; i < SchemeLast; i++) + free(scheme[i]); + drw_free(drw); + XSync(dpy, False); + XCloseDisplay(dpy); +} + +static char * +cistrstr(const char *s, const char *sub) +{ + size_t len; + + for (len = strlen(sub); *s; s++) + if (!strncasecmp(s, sub, len)) + return (char *)s; + return NULL; +} + +static int +drawitem(struct item *item, int x, int y, int w) +{ + if (item == sel) + drw_setscheme(drw, scheme[SchemeSel]); + else if (item->out) + drw_setscheme(drw, scheme[SchemeOut]); + else + drw_setscheme(drw, scheme[SchemeNorm]); + + return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0); +} + +static void +drawmenu(void) +{ + unsigned int curpos; + struct item *item; + int x = 0, y = 0, w; + + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, 0, 0, mw, mh, 1, 1); + + if (prompt && *prompt) { + drw_setscheme(drw, scheme[SchemeSel]); + x = drw_text(drw, x, 0, promptw, bh, lrpad / 2, prompt, 0); + } + /* draw input field */ + w = (lines > 0 || !matches) ? mw - x : inputw; + drw_setscheme(drw, scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0); + + curpos = TEXTW(text) - TEXTW(&text[cursor]); + if ((curpos += lrpad / 2 - 1) < w) { + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0); + } + + if (lines > 0) { + /* draw vertical list */ + for (item = curr; item != next; item = item->right) + drawitem(item, x, y += bh, mw - x); + } else if (matches) { + /* draw horizontal list */ + x += inputw; + w = TEXTW("<"); + if (curr->left) { + drw_setscheme(drw, scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, "<", 0); + } + x += w; + for (item = curr; item != next; item = item->right) + x = drawitem(item, x, 0, MIN(TEXTW(item->text), mw - x - TEXTW(">"))); + if (next) { + w = TEXTW(">"); + drw_setscheme(drw, scheme[SchemeNorm]); + drw_text(drw, mw - w, 0, w, bh, lrpad / 2, ">", 0); + } + } + drw_map(drw, win, 0, 0, mw, mh); +} + +static void +grabfocus(void) +{ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; + Window focuswin; + int i, revertwin; + + for (i = 0; i < 100; ++i) { + XGetInputFocus(dpy, &focuswin, &revertwin); + if (focuswin == win) + return; + XSetInputFocus(dpy, win, RevertToParent, CurrentTime); + nanosleep(&ts, NULL); + } + die("cannot grab focus"); +} + +static void +grabkeyboard(void) +{ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 }; + int i; + + if (embed) + return; + /* try to grab keyboard, we may have to wait for another process to ungrab */ + for (i = 0; i < 1000; i++) { + if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, + GrabModeAsync, CurrentTime) == GrabSuccess) + return; + nanosleep(&ts, NULL); + } + die("cannot grab keyboard"); +} + +static void +match(void) +{ + static char **tokv = NULL; + static int tokn = 0; + + char buf[sizeof text], *s; + int i, tokc = 0; + size_t len, textsize; + struct item *item, *lprefix, *lsubstr, *prefixend, *substrend; + + strcpy(buf, text); + /* separate input text into tokens to be matched individually */ + for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " ")) + if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv))) + die("cannot realloc %u bytes:", tokn * sizeof *tokv); + len = tokc ? strlen(tokv[0]) : 0; + + matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL; + textsize = strlen(text) + 1; + for (item = items; item && item->text; item++) { + for (i = 0; i < tokc; i++) + if (!fstrstr(item->text, tokv[i])) + break; + if (i != tokc) /* not all tokens match */ + continue; + /* exact matches go first, then prefixes, then substrings */ + if (!tokc || !fstrncmp(text, item->text, textsize)) + appenditem(item, &matches, &matchend); + else if (!fstrncmp(tokv[0], item->text, len)) + appenditem(item, &lprefix, &prefixend); + else + appenditem(item, &lsubstr, &substrend); + } + if (lprefix) { + if (matches) { + matchend->right = lprefix; + lprefix->left = matchend; + } else + matches = lprefix; + matchend = prefixend; + } + if (lsubstr) { + if (matches) { + matchend->right = lsubstr; + lsubstr->left = matchend; + } else + matches = lsubstr; + matchend = substrend; + } + curr = sel = matches; + calcoffsets(); +} + +static void +insert(const char *str, ssize_t n) +{ + if (strlen(text) + n > sizeof text - 1) + return; + /* move existing text out of the way, insert new text, and update cursor */ + memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0)); + if (n > 0) + memcpy(&text[cursor], str, n); + cursor += n; + match(); +} + +static size_t +nextrune(int inc) +{ + ssize_t n; + + /* return location of next utf8 rune in the given direction (+1 or -1) */ + for (n = cursor + inc; n + inc >= 0 && (text[n] & 0xc0) == 0x80; n += inc) + ; + return n; +} + +static void +movewordedge(int dir) +{ + if (dir < 0) { /* move cursor to the start of the word*/ + while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)])) + cursor = nextrune(-1); + while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)])) + cursor = nextrune(-1); + } else { /* move cursor to the end of the word */ + while (text[cursor] && strchr(worddelimiters, text[cursor])) + cursor = nextrune(+1); + while (text[cursor] && !strchr(worddelimiters, text[cursor])) + cursor = nextrune(+1); + } +} + +static void +keypress(XKeyEvent *ev) +{ + char buf[32]; + int len; + KeySym ksym; + Status status; + + len = XmbLookupString(xic, ev, buf, sizeof buf, &ksym, &status); + switch (status) { + default: /* XLookupNone, XBufferOverflow */ + return; + case XLookupChars: + goto insert; + case XLookupKeySym: + case XLookupBoth: + break; + } + + if (ev->state & ControlMask) { + switch(ksym) { + case XK_a: ksym = XK_Home; break; + case XK_b: ksym = XK_Left; break; + case XK_c: ksym = XK_Escape; break; + case XK_d: ksym = XK_Delete; break; + case XK_e: ksym = XK_End; break; + case XK_f: ksym = XK_Right; break; + case XK_g: ksym = XK_Escape; break; + case XK_h: ksym = XK_BackSpace; break; + case XK_i: ksym = XK_Tab; break; + case XK_j: /* fallthrough */ + case XK_J: /* fallthrough */ + case XK_m: /* fallthrough */ + case XK_M: ksym = XK_Return; ev->state &= ~ControlMask; break; + case XK_n: ksym = XK_Down; break; + case XK_p: ksym = XK_Up; break; + + case XK_k: /* delete right */ + text[cursor] = '\0'; + match(); + break; + case XK_u: /* delete left */ + insert(NULL, 0 - cursor); + break; + case XK_w: /* delete word */ + while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)])) + insert(NULL, nextrune(-1) - cursor); + while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)])) + insert(NULL, nextrune(-1) - cursor); + break; + case XK_y: /* paste selection */ + case XK_Y: + XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY, + utf8, utf8, win, CurrentTime); + return; + case XK_Left: + movewordedge(-1); + goto draw; + case XK_Right: + movewordedge(+1); + goto draw; + case XK_Return: + case XK_KP_Enter: + break; + case XK_bracketleft: + cleanup(); + exit(1); + default: + return; + } + } else if (ev->state & Mod1Mask) { + switch(ksym) { + case XK_b: + movewordedge(-1); + goto draw; + case XK_f: + movewordedge(+1); + goto draw; + case XK_g: ksym = XK_Home; break; + case XK_G: ksym = XK_End; break; + case XK_h: ksym = XK_Up; break; + case XK_j: ksym = XK_Next; break; + case XK_k: ksym = XK_Prior; break; + case XK_l: ksym = XK_Down; break; + default: + return; + } + } + + switch(ksym) { + default: +insert: + if (!iscntrl(*buf)) + insert(buf, len); + break; + case XK_Delete: + if (text[cursor] == '\0') + return; + cursor = nextrune(+1); + /* fallthrough */ + case XK_BackSpace: + if (cursor == 0) + return; + insert(NULL, nextrune(-1) - cursor); + break; + case XK_End: + if (text[cursor] != '\0') { + cursor = strlen(text); + break; + } + if (next) { + /* jump to end of list and position items in reverse */ + curr = matchend; + calcoffsets(); + curr = prev; + calcoffsets(); + while (next && (curr = curr->right)) + calcoffsets(); + } + sel = matchend; + break; + case XK_Escape: + cleanup(); + exit(1); + case XK_Home: + if (sel == matches) { + cursor = 0; + break; + } + sel = curr = matches; + calcoffsets(); + break; + case XK_Left: + if (cursor > 0 && (!sel || !sel->left || lines > 0)) { + cursor = nextrune(-1); + break; + } + if (lines > 0) + return; + /* fallthrough */ + case XK_Up: + if (sel && sel->left && (sel = sel->left)->right == curr) { + curr = prev; + calcoffsets(); + } + break; + case XK_Next: + if (!next) + return; + sel = curr = next; + calcoffsets(); + break; + case XK_Prior: + if (!prev) + return; + sel = curr = prev; + calcoffsets(); + break; + case XK_Return: + case XK_KP_Enter: + puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); + if (!(ev->state & ControlMask)) { + cleanup(); + exit(0); + } + if (sel) + sel->out = 1; + break; + case XK_Right: + if (text[cursor] != '\0') { + cursor = nextrune(+1); + break; + } + if (lines > 0) + return; + /* fallthrough */ + case XK_Down: + if (sel && sel->right && (sel = sel->right) == next) { + curr = next; + calcoffsets(); + } + break; + case XK_Tab: + if (!sel) + return; + strncpy(text, sel->text, sizeof text - 1); + text[sizeof text - 1] = '\0'; + cursor = strlen(text); + match(); + break; + } + +draw: + drawmenu(); +} + +static void +paste(void) +{ + char *p, *q; + int di; + unsigned long dl; + Atom da; + + /* we have been given the current selection, now insert it into input */ + if (XGetWindowProperty(dpy, win, utf8, 0, (sizeof text / 4) + 1, False, + utf8, &da, &di, &dl, &dl, (unsigned char **)&p) + == Success && p) { + insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t)strlen(p)); + XFree(p); + } + drawmenu(); +} + +static void +readstdin(void) +{ + char buf[sizeof text], *p; + size_t i, imax = 0, size = 0; + unsigned int tmpmax = 0; + + /* read each line from stdin and add it to the item list */ + for (i = 0; fgets(buf, sizeof buf, stdin); i++) { + if (i + 1 >= size / sizeof *items) + if (!(items = realloc(items, (size += BUFSIZ)))) + die("cannot realloc %u bytes:", size); + if ((p = strchr(buf, '\n'))) + *p = '\0'; + if (!(items[i].text = strdup(buf))) + die("cannot strdup %u bytes:", strlen(buf) + 1); + items[i].out = 0; + drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL); + if (tmpmax > inputw) { + inputw = tmpmax; + imax = i; + } + } + if (items) + items[i].text = NULL; + inputw = items ? TEXTW(items[imax].text) : 0; + lines = MIN(lines, i); +} + +static void +run(void) +{ + XEvent ev; + + while (!XNextEvent(dpy, &ev)) { + if (XFilterEvent(&ev, win)) + continue; + switch(ev.type) { + case DestroyNotify: + if (ev.xdestroywindow.window != win) + break; + cleanup(); + exit(1); + case Expose: + if (ev.xexpose.count == 0) + drw_map(drw, win, 0, 0, mw, mh); + break; + case FocusIn: + /* regrab focus from parent window */ + if (ev.xfocus.window != win) + grabfocus(); + break; + case KeyPress: + keypress(&ev.xkey); + break; + case SelectionNotify: + if (ev.xselection.property == utf8) + paste(); + break; + case VisibilityNotify: + if (ev.xvisibility.state != VisibilityUnobscured) + XRaiseWindow(dpy, win); + break; + } + } +} + +static void +setup(void) +{ + int x, y, i, j; + unsigned int du; + XSetWindowAttributes swa; + XIM xim; + Window w, dw, *dws; + XWindowAttributes wa; + XClassHint ch = {"dmenu", "dmenu"}; +#ifdef XINERAMA + XineramaScreenInfo *info; + Window pw; + int a, di, n, area = 0; +#endif + /* init appearance */ + for (j = 0; j < SchemeLast; j++) + scheme[j] = drw_scm_create(drw, colors[j], 2); + + clip = XInternAtom(dpy, "CLIPBOARD", False); + utf8 = XInternAtom(dpy, "UTF8_STRING", False); + + /* calculate menu geometry */ + bh = drw->fonts->h + 2; + lines = MAX(lines, 0); + mh = (lines + 1) * bh; + promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; +#ifdef XINERAMA + i = 0; + if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) { + XGetInputFocus(dpy, &w, &di); + if (mon >= 0 && mon < n) + i = mon; + else if (w != root && w != PointerRoot && w != None) { + /* find top-level window containing current input focus */ + do { + if (XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws) + XFree(dws); + } while (w != root && w != pw); + /* find xinerama screen with which the window intersects most */ + if (XGetWindowAttributes(dpy, pw, &wa)) + for (j = 0; j < n; j++) + if ((a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j])) > area) { + area = a; + i = j; + } + } + /* no focused window is on screen, so use pointer location instead */ + if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) + for (i = 0; i < n; i++) + if (INTERSECT(x, y, 1, 1, info[i])) + break; + + if (centered) { + mw = MIN(MAX(max_textw() + promptw, min_width), info[i].width); + x = info[i].x_org + ((info[i].width - mw) / 2); + y = info[i].y_org + ((info[i].height - mh) / 2); + } else { + x = info[i].x_org; + y = info[i].y_org + (topbar ? 0 : info[i].height - mh); + mw = info[i].width; + } + XFree(info); + } else +#endif + { + if (!XGetWindowAttributes(dpy, parentwin, &wa)) + die("could not get embedding window attributes: 0x%lx", + parentwin); + + if (centered) { + mw = MIN(MAX(max_textw() + promptw, min_width), wa.width); + x = (wa.width - mw) / 2; + y = (wa.height - mh) / 2; + } else { + x = 0; + y = topbar ? 0 : wa.height - mh; + mw = wa.width; + } + } + inputw = MIN(inputw, mw/3); + match(); + + /* create menu window */ + swa.override_redirect = True; + swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; + swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; + win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0, + CopyFromParent, CopyFromParent, CopyFromParent, + CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); + XSetClassHint(dpy, win, &ch); + + + /* input methods */ + if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL) + die("XOpenIM failed: could not open input device"); + + xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, win, XNFocusWindow, win, NULL); + + XMapRaised(dpy, win); + if (embed) { + XSelectInput(dpy, parentwin, FocusChangeMask | SubstructureNotifyMask); + if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) { + for (i = 0; i < du && dws[i] != win; ++i) + XSelectInput(dpy, dws[i], FocusChangeMask); + XFree(dws); + } + grabfocus(); + } + drw_resize(drw, mw, mh); + drawmenu(); +} + +static void +usage(void) +{ + fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" + " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + XWindowAttributes wa; + int i, fast = 0; + + for (i = 1; i < argc; i++) + /* these options take no arguments */ + if (!strcmp(argv[i], "-v")) { /* prints version information */ + puts("dmenu-"VERSION); + exit(0); + } else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */ + topbar = 0; + else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ + fast = 1; + else if (!strcmp(argv[i], "-c")) /* centers dmenu on screen */ + centered = 1; + else if (!strcmp(argv[i], "-s")) { /* case-sensitive item matching */ + fstrncmp = strncmp; + fstrstr = strstr; + } else if (i + 1 == argc) + usage(); + /* these options take one argument */ + else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */ + lines = atoi(argv[++i]); + else if (!strcmp(argv[i], "-m")) + mon = atoi(argv[++i]); + else if (!strcmp(argv[i], "-p")) /* adds prompt to left of input field */ + prompt = argv[++i]; + else if (!strcmp(argv[i], "-fn")) /* font or font set */ + fonts[0] = argv[++i]; + else if (!strcmp(argv[i], "-nb")) /* normal background color */ + colors[SchemeNorm][ColBg] = argv[++i]; + else if (!strcmp(argv[i], "-nf")) /* normal foreground color */ + colors[SchemeNorm][ColFg] = argv[++i]; + else if (!strcmp(argv[i], "-sb")) /* selected background color */ + colors[SchemeSel][ColBg] = argv[++i]; + else if (!strcmp(argv[i], "-sf")) /* selected foreground color */ + colors[SchemeSel][ColFg] = argv[++i]; + else if (!strcmp(argv[i], "-w")) /* embedding window id */ + embed = argv[++i]; + else + usage(); + + if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) + fputs("warning: no locale support\n", stderr); + if (!(dpy = XOpenDisplay(NULL))) + die("cannot open display"); + screen = DefaultScreen(dpy); + root = RootWindow(dpy, screen); + if (!embed || !(parentwin = strtol(embed, NULL, 0))) + parentwin = root; + if (!XGetWindowAttributes(dpy, parentwin, &wa)) + die("could not get embedding window attributes: 0x%lx", + parentwin); + drw = drw_create(dpy, screen, root, wa.width, wa.height); + if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) + die("no fonts could be loaded."); + lrpad = drw->fonts->h; + +#ifdef __OpenBSD__ + if (pledge("stdio rpath", NULL) == -1) + die("pledge"); +#endif + + if (fast && !isatty(0)) { + grabkeyboard(); + readstdin(); + } else { + readstdin(); + grabkeyboard(); + } + setup(); + run(); + + return 1; /* unreachable */ +} diff --git a/dmenu.o b/dmenu.o index e40b7fe44379e124c3336d635039c8751fe42372..ab0861e2f2cd1b19701088fce7e958dfaaa76244 100644 GIT binary patch literal 33904 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 hTNAzrHZ*N77~_80OFtOK--GAW&) z_$9Q@<+7gRkW_kncY;ZtznF)A*HZQea4$8c$DMYI*7aflC4v+}Oa7w(C=2g?V%At}~q0 zUm{M;Llpk41eH51P3#7iCDUlwL7O`NYRZ2gAk}^671I!GpkLz{(3(A?A zIDp$aetaLtzpth9^L`O*3>3dWg;m^pj$LE?unZkPlwtYQ?P1HNJI}Xk{kw!Zeq|sV zsQk`mo1gzZC6+-P+V);7$ok4(*s2X+${sz)pc4I!Q1}gs_H`wEycI9CCcnQ_z zUk_}c@`qnwGqT?9_2uV%tmZ)FKeEy)xSwMA*caIz^HyM3e!npV_5)Nt=93Avn0VbG zw#@gYdvD$T1(aX=#r|{t-@*pk)cF@v{*9_(b^b>n??Ca}N%31u z4r3hf($D!hegl;aGAEFSe;sE&UFT1O?J8JwetgZNTm<4c@LwV~iT~ZT-8(*h=+i*? S^YNp6NSo~{{gd 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 I>?9+90aO^dEdT%j delta 1420 zcmZ9MJxml)6oqFQP!?v?;qN)J!~U|nfE!|r2^tqxV-yvXV1oq(#25;RRz?dVYE2}b zLK+GZDTzN@Xk#L=*@nWzmKX~XG$Fx`f{mWHGh?pYWcS|pzIV>M^XBdDjnCg&%qt^n z{EJepDj7!%``u8~E^fJ?EsI9JjVa0jEg>|L@$LZj@ zD2}%LZ1UF~W-9+`X^Ofwt2;G;VYCLhj@gDCQ*I}#{Xc#@6Eub*=`leO(0XPMv!q>u zz6q#yj$xTpHyk>D4ydo)AdL&U6;NMWC2bM(x6md~@RY5eB6N;mJ*6 z-YKSmD?`puAmtd;|lla_(C_w&}jg()SPD( zI^GX1n5IKmCY5LN@DQgNzIKE3EJvYsUC;}tlIpvs-E}PJE6LD@V55*w?nPFicDhkB z-+2&|31ts*6jBc>Nrk0^WnU7rGx*BcO2TqG#O%{32Mpa~5d+;w9GK(gA37Ip31(8G~DG>1l3$8Ci02G6i3>*#E* +Date: Sat, 11 Jan 2020 21:16:08 -0600 +Subject: [PATCH] center patch now has adjustable minimum width + +--- + config.def.h | 2 ++ + dmenu.1 | 3 +++ + dmenu.c | 39 ++++++++++++++++++++++++++++++++------- + 3 files changed, 37 insertions(+), 7 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1edb647..88ef264 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -2,6 +2,8 @@ + /* Default settings; can be overriden by command line. */ + + static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */ ++static int centered = 0; /* -c option; centers dmenu on screen */ ++static int min_width = 500; /* minimum width when centered */ + /* -fn option overrides fonts[0]; default X11 font or font set */ + static const char *fonts[] = { + "monospace:size=10" +diff --git a/dmenu.1 b/dmenu.1 +index 323f93c..c036baa 100644 +--- a/dmenu.1 ++++ b/dmenu.1 +@@ -40,6 +40,9 @@ which lists programs in the user's $PATH and runs the result in their $SHELL. + .B \-b + dmenu appears at the bottom of the screen. + .TP ++.B \-c ++dmenu appears centered on the screen. ++.TP + .B \-f + dmenu grabs the keyboard before reading stdin if not reading from a tty. This + is faster, but will lock up X until stdin reaches end\-of\-file. +diff --git a/dmenu.c b/dmenu.c +index 65f25ce..041c7f8 100644 +--- a/dmenu.c ++++ b/dmenu.c +@@ -89,6 +89,15 @@ calcoffsets(void) + break; + } + ++static int ++max_textw(void) ++{ ++ int len = 0; ++ for (struct item *item = items; item && item->text; item++) ++ len = MAX(TEXTW(item->text), len); ++ return len; ++} ++ + static void + cleanup(void) + { +@@ -611,6 +620,7 @@ setup(void) + bh = drw->fonts->h + 2; + lines = MAX(lines, 0); + mh = (lines + 1) * bh; ++ promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; + #ifdef XINERAMA + i = 0; + if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) { +@@ -637,9 +647,16 @@ setup(void) + if (INTERSECT(x, y, 1, 1, info[i])) + break; + +- x = info[i].x_org; +- y = info[i].y_org + (topbar ? 0 : info[i].height - mh); +- mw = info[i].width; ++ if (centered) { ++ mw = MIN(MAX(max_textw() + promptw, min_width), info[i].width); ++ x = info[i].x_org + ((info[i].width - mw) / 2); ++ y = info[i].y_org + ((info[i].height - mh) / 2); ++ } else { ++ x = info[i].x_org; ++ y = info[i].y_org + (topbar ? 0 : info[i].height - mh); ++ mw = info[i].width; ++ } ++ + XFree(info); + } else + #endif +@@ -647,11 +664,17 @@ setup(void) + if (!XGetWindowAttributes(dpy, parentwin, &wa)) + die("could not get embedding window attributes: 0x%lx", + parentwin); +- x = 0; +- y = topbar ? 0 : wa.height - mh; +- mw = wa.width; ++ ++ if (centered) { ++ mw = MIN(MAX(max_textw() + promptw, min_width), wa.width); ++ x = (wa.width - mw) / 2; ++ y = (wa.height - mh) / 2; ++ } else { ++ x = 0; ++ y = topbar ? 0 : wa.height - mh; ++ mw = wa.width; ++ } + } +- promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; + inputw = MIN(inputw, mw/3); + match(); + +@@ -709,6 +732,8 @@ main(int argc, char *argv[]) + topbar = 0; + else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ + fast = 1; ++ else if (!strcmp(argv[i], "-c")) /* centers dmenu on screen */ ++ centered = 1; + else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ + fstrncmp = strncasecmp; + fstrstr = cistrstr; +-- +2.24.1 + diff --git a/stest b/stest index c93eed0aabd6b4ee4f747c9cb34b7bb157cf0469..c1f1031522d662191b2ba02dafa5d5ce56e7e9a4 100755 GIT binary patch delta 3019 zcmZuzeQZ-z6uY|lmIpm)F362h%w5LKU9K>2_`5a5KtHb&vV|pcdUi8-21!toZtC) z_q}_%!7cpgCf@g?t=7wiCBSM~0SmARtTf?wPybQTEfP(FXh1aLu+t(96We`xyYh7H zuDry#^4xVf`feSVxhL-u*LRmV%;&GgYej%e4CpMZL>HNulG5lAewi2+e2K&*dG`0% z3R-9689S^95DO)s&5W5~h?nKcFkzUi?2eO(f>hwh!ZCNjVy5)66zRlcA@a1nlCdZ5 zXdF~O`44=0`p7Ak_4Bc5TQ?eyZ14Fg=et*kQ;dUR5{CqJ*;;Z2+^~e7g}nwFbQ&7? z32ilKu=De@+HSP-O|;1R2)!mkP_e>t)a}q{eYkoTP8dD>Gi`4-+QF1%=eudgduevm zVcKHmU(F(}V|9{RIa zDpgf5lwIjHFh%<_iWv_OS2RdC9#p9oTHCT@VrMoThM#n>IOhkR2h&W)d4BSW>FMlG zipMF&>-SX^oR$ei2XJxO*|2TS?E=Ow1)stnzO!0F~+x}dwCodjCsyj_aAQG8?%|e1D=vbd($0N-IOZYkt#Zp zx?J)FRoZ}Y>HtdS^W*SK$?Np?ZWK+p)3EU`Q^UrSrZ1E3iEo;=yOz%hpoK2P$*Zaw zBfO@n=Mf*jp{h#}OK+-bKVlg1AmWaHRdp&ptnn7|VZZA!o`N$j8*hL=TxEPcnB7*s z6`pWU;TNFEy^t@5y>9;~%3qCMoBzSWn<}lziith>a3MDcA560ce?uz?5;VCYQ10(% z?9IX;?WMrWoxBa)@aS`c0khJ0JArZiCL!!LHQjx1`MJr$d6IeVxHxplvs;V7C zkO}ZiwEd}MmnXtu&|rkARb!1t)^C9MRbgHTZ&leGg=~Os5=x`~v1k{QGY1?;tAnwi zZtc^7%|ayW)hZizKu)y>BOJ5}qku(-3M+(#)fC?);!6&F{1hRM*3sI^u;Kuxx_ zh_zwSBPF3R4iMY%4aPN7?{eu3>SQG6G|pv>lZE+;A5oJ9nlaxbNZ=f#b$l^0AJuDG zNw3(4dyt-kv2LN?6_6Sodr?nMc&$X=M}@gh#J>>G6|$G@)c6cqXPO-!;+neQfZzyM zc37)+5H{47S|9F}7s=`vLSL#sl@Wgw9ICZ(r#4s6>Nulc zeY*QHU_d$wye62L2P7Vly)FFf1yBBdNNl51K_P!?NAiGme>|DJa3U5E9i9ZM>6@!#Il)5EPz8kCr`o|^!psl^-dlpjr(iiCm(3Qg$fjj4bX+$vyiCw z^Izc%&X>U)DszZ~A1)AEqb4_@DdguvkO=t|g~RtDpJL)*3Hy`+4$p*_703$5BYiv^ a3s1>CTBEzR!1eIV+;MgKt^^MGo&N*T%KJ+I delta 3407 zcmZuzeQ;FO6+idA%_bXMvL8uawh7r?sw4rMP1b-}^06<08B>jX%)~lv8J9Ffk|`x2 zL=B8Hu~VX=Q=8;~qZFpGMa?)k1_KH@%F^+ljX%)Jv0saLIx^Lu17FsD z-^8sI(w|$tZ_PvSczpHoz3H{yKxky!muGIiv9sxr#T*~~h2)U3`5GSA9~P(4?@EdH zahoe9{)Vr(VmO*pBK}UOk@G4s7vo_qI8M+D3}FqG4sc0)W!oFcK7wO8F|n8J@j6$j z4@zLFm0OvWI5qAA0}I?nZ3#@68IPK`gzcThRlR4Z;D-`?*gc9D-5Y$V)X?_9&Ou0} zw%7%1%iWCcf1A~cU)qQ~;xfSK1grQsv#G0dR(zYzCkNK)WnoQgFO>c{( z1g16Duue{O-eqW8@y1lgcrLEP1>OM;(dh&Ob*x5*?tV2Gi>B;u$bR*jLiVbG9ufrV>;gxlW4qk}(9Uz%HEQEu` z?eGGC$n9_+Y;fXi>vUO6IUP10fJqcJ!5kfeFvTTZheEVsMO``+!6!)~IYftI0Mh}I zse=Kdx5ejQUtC*<5T2-sxp=YhO3mt!7k0=KP{DqZW%Sp;i)(9*Pzji=HV8c#13ypK}?d@3;o%r zlRU?4Zvgw^F_$0iT#SE=-z|K2CTf%#!j$$%OCxs4Z zUT}7$7i;SbF@)zR!gKr`uX6|IZ`b|o3cW9bILH5I4ifsDyndM7(wvrAF51B@n-ik$ zQJS2$!K?{5V+PN(1TZ1-mrR9Z^qYk9v|Oe| zW$Df+_&~=0!ps0FVgJSE1HQZ5ANrWeobo3mM^=Te?A}`RT@;-EASgut3PUXAZ^)!; zjYpAow9;X7dTh><#NnB7w(=YH=DtK;>i_iXE4oF4d0+dFTUVvx)$!`({8W%nhRwg~ z+nS>Cz+fr`{f`Z9H|G$$hk6H1Y^)Cl=fEkhGKf9ya@a`m)M7 zo`LSpO`CcL=C-nZa8vJA69b7=*pXOTHB+GuHg^wh>D}5rm#!We<#Y&vobmT^OeN{hZ=l-m8_I5!;>{ZJk(H@uhP{i4Fio! z@H&xIrcyeBp~i64YFcZ0H}ugCutnu9rRyc0gXbHJsx@R$%Ak{)5ngr{rTeABjprMU z#Xlhr6BJwJZKXE~+}BWE^$1ZoJ1d&XcuLoipCt!7n~bVoQi&dSGi;Rym9DY50B(GR z*gMJMQ>tRC?5Ol*$)@2o87=(EVs@)URnDBzbpBcR{lUjfouv{6NnXH2b5iWa9rWFU z$D6}q7k=6t4(%f!S5*%dl`0RSKUpCrFp*4(N!*bPiw<6t#qUVI>b1&7_YUf_O Zt96;DKS4#31NhU{d-J{W*4FI>`ahg@EN=h+ diff --git a/stest.o b/stest.o index 9408acc32b22a0b093552dc7cacd070a1e9a4780..c7926cec7aa2152edb0566d0edeafe9af99b6459 100644 GIT binary patch delta 1040 zcmY+DPe@cj9LHzW-NmUd891XC5`D^`ynQ9w;m$7BA4V@ikEsSq!jbqcn)88YeaGj{m*a{;= zFB4r!(T7B@68)5-8%QHmlDfMox=r4j_igIRl)NV_ZvmbY-6VS2 zq6c70D0n7Zp?@14CgVP;c-v6+jy6x@uz~Ck^=8(Hr-Vc$xrGvZcNIML+}O3$3f0v+ zIS3nGl^=p_PsKWC;(TGvDM86s@W6BVJ6Q7+)O|NDTXTQVT(gEbU&X?rdse0+u<8#9 zeVZRh9fU`?vyR{-cVIZU6;4dfjP+ibxY0W`JvlWtJu?emf(uX%>)|B_Z5TCe#}MoH z!zvFOx)w%q0Rlc3mS9=7@f`e;vi&xlV;|g+o%}A0O2uEntnA|RFdC}jH{bYcreiuC iJ}y})*0V+HaZw=_hi;B+6o5-#MVP?PI%)FWRNUOeCe^}FBLh;X< z-KZ(bBG{RpDPp_$Lps%| zy2SJ&Q`0ZSeWtgV4zRc9?lOJAYMs5QJ%SF?+uZSLu6EeBQzfjf=I9*L=d8ZS(N&@; zb?x2NevWQ&ZJX6jj(+~HHZ`k|*?pC=Q*Cq2Nv3w+Q;J?r`Kp;y7pdkbb?8lVEz_}z z4eoe}JD%yDCWJ{!u%{Z5-j8#7FY}Xg%uGX=3N#J^Url882r(aMc?>H-BORfv-r3+B zQ+XV_flfy=^mT@gp+j^$L*HlU2@IF*P26MkfW4VJ!dzL)30yCqrs=mRuHqfVK2&%I zPr`Hf8eWWA9;K4aI@bH`^HD=a-<18V@iqB)H2Ao*OrklVfbWAEYw<|wCViPTnpjS> rnx)8?Pd^Wz;>k+Q?FypB?M>Slm1I)xV!_@P?TSg zT2xXwxq~%e@&!iL$v0Rd1ZOZq4C8?6=HBec7S6~T2^3|YJeOUX(O_~Rlj!7g>|BzC zKrxUikOjzK!Q_qX>bf~VA&^%ckfng^1t38nFn~}D+(4RhGAoC+=m)5k0Z^I;D8n+@ Xl|!4+VR9jdJ=X=O&T59qzgXn}{SQ|1 delta 384 zcmca0ctdc4hWHFt1~_m4vm6+B8F)6@8!}E_z&K;F0uvh}^W=|=qRh+;EKr&iO0$D# zR%Qkc28PLn?4pzHn1sOU**4oVr7}u#1C9Ih9|BfFEnxxDyp#7bi=)UMLXzd1{1zz7 zkEHiLlB~dFSr$~;uSl|jlYN1*!bp1A86nb4K#F5>EsHoK*W{@zQzzT9`c0m|8X@?D z86wXCRmZjYCu=w(W8CD4?BbjSP{9D8@8l;3u(M3Q!YU%l01Yt%h)xDBu+e|nwM7p= f)jxpJpa9^SY|Ej|xL|T7hdrkORA