Browse Source

merge default -> lsx

master
Connor Lane Smith 13 years ago
parent
commit
4126b1e323
9 changed files with 118 additions and 119 deletions
  1. +1
    -0
      .hgtags
  2. +2
    -2
      Makefile
  3. +1
    -1
      config.mk
  4. +6
    -9
      dmenu.1
  5. +93
    -93
      dmenu.c
  6. +1
    -1
      dmenu_run
  7. +11
    -11
      draw.c
  8. +1
    -0
      draw.h
  9. +2
    -2
      lsx.c

+ 1
- 0
.hgtags View File

@ -46,3 +46,4 @@ e4c81a78ffbad6ba4d1ad119cc654da6eca63a4c 3.2
abb6579a324fffdf6a23c2fa4c32911277da594a 4.2.1 abb6579a324fffdf6a23c2fa4c32911277da594a 4.2.1
14c79f054bdf43ff3213af8e60a783192e92a018 4.3 14c79f054bdf43ff3213af8e60a783192e92a018 4.3
34a2d77049a95b02f3332a0b88f9370965ebcfad 4.3.1 34a2d77049a95b02f3332a0b88f9370965ebcfad 4.3.1
2b105eaae8315b076da93056da9ecd60de5a7ac9 4.4

+ 2
- 2
Makefile View File

@ -30,12 +30,12 @@ lsx: lsx.o
clean: clean:
@echo cleaning @echo cleaning
@rm -f dmenu ${OBJ} dmenu-${VERSION}.tar.gz
@rm -f dmenu lsx ${OBJ} dmenu-${VERSION}.tar.gz
dist: clean dist: clean
@echo creating dist tarball @echo creating dist tarball
@mkdir -p dmenu-${VERSION} @mkdir -p dmenu-${VERSION}
@cp LICENSE Makefile README config.mk dmenu.1 draw.h dmenu_run ${SRC} dmenu-${VERSION}
@cp LICENSE Makefile README config.mk dmenu.1 draw.h dmenu_run lsx.1 ${SRC} dmenu-${VERSION}
@tar -cf dmenu-${VERSION}.tar dmenu-${VERSION} @tar -cf dmenu-${VERSION}.tar dmenu-${VERSION}
@gzip dmenu-${VERSION}.tar @gzip dmenu-${VERSION}.tar
@rm -rf dmenu-${VERSION} @rm -rf dmenu-${VERSION}


+ 1
- 1
config.mk View File

@ -1,5 +1,5 @@
# dmenu version # dmenu version
VERSION = 4.3.1
VERSION = hg
# paths # paths
PREFIX = /usr/local PREFIX = /usr/local


+ 6
- 9
dmenu.1 View File

@ -25,13 +25,10 @@ dmenu \- dynamic menu
.BR dmenu_run " ..." .BR dmenu_run " ..."
.SH DESCRIPTION .SH DESCRIPTION
.B dmenu .B dmenu
is a dynamic menu for X, originally designed for
.IR dwm (1).
It manages huge numbers of user\-defined menu items efficiently.
.P
dmenu reads a list of newline\-separated items from stdin and creates a menu.
When the user selects an item or enters any text and presses Return, their
choice is printed to stdout and dmenu terminates.
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 .P
.B dmenu_run .B dmenu_run
is a dmenu script used by dwm which lists programs in the user's $PATH and is a dmenu script used by dwm which lists programs in the user's $PATH and
@ -42,8 +39,8 @@ executes the selected item.
dmenu appears at the bottom of the screen. dmenu appears at the bottom of the screen.
.TP .TP
.B \-f .B \-f
dmenu grabs the keyboard before reading stdin. This is faster, but may lock up
X if stdin is from a terminal.
dmenu grabs the keyboard before reading stdin. This is faster, but will lock up
X until stdin reaches end\-of\-file.
.TP .TP
.B \-i .B \-i
dmenu matches menu items case insensitively. dmenu matches menu items case insensitively.


+ 93
- 93
dmenu.c View File

@ -25,12 +25,12 @@ struct Item {
static void appenditem(Item *item, Item **list, Item **last); static void appenditem(Item *item, Item **list, Item **last);
static void calcoffsets(void); static void calcoffsets(void);
static char *cistrstr(const char *s, const char *sub);
static void drawmenu(void); static void drawmenu(void);
static char *fstrstr(const char *s, const char *sub);
static void grabkeyboard(void); static void grabkeyboard(void);
static void insert(const char *str, ssize_t n); static void insert(const char *str, ssize_t n);
static void keypress(XKeyEvent *ev); static void keypress(XKeyEvent *ev);
static void match(Bool sub);
static void match(void);
static size_t nextrune(int inc); static size_t nextrune(int inc);
static void paste(void); static void paste(void);
static void readstdin(void); static void readstdin(void);
@ -60,6 +60,7 @@ static Item *prev, *curr, *next, *sel;
static Window win; static Window win;
static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
static char *(*fstrstr)(const char *, const char *) = strstr;
int int
main(int argc, char *argv[]) { main(int argc, char *argv[]) {
@ -76,8 +77,10 @@ main(int argc, char *argv[]) {
topbar = False; topbar = False;
else if(!strcmp(argv[i], "-f")) else if(!strcmp(argv[i], "-f"))
fast = True; fast = True;
else if(!strcmp(argv[i], "-i"))
else if(!strcmp(argv[i], "-i")) {
fstrncmp = strncasecmp; fstrncmp = strncasecmp;
fstrstr = cistrstr;
}
else if(i+1 == argc) else if(i+1 == argc)
usage(); usage();
/* double flags */ /* double flags */
@ -112,15 +115,16 @@ main(int argc, char *argv[]) {
setup(); setup();
run(); run();
return EXIT_FAILURE; /* should not reach */
return EXIT_FAILURE; /* unreachable */
} }
void void
appenditem(Item *item, Item **list, Item **last) { appenditem(Item *item, Item **list, Item **last) {
if(!*last)
*list = item;
else
if(*last)
(*last)->right = item; (*last)->right = item;
else
*list = item;
item->left = *last; item->left = *last;
item->right = NULL; item->right = NULL;
*last = item; *last = item;
@ -143,6 +147,16 @@ calcoffsets(void) {
break; break;
} }
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;
}
void void
drawmenu(void) { drawmenu(void) {
int curpos; int curpos;
@ -188,16 +202,6 @@ drawmenu(void) {
mapdc(dc, win, mw, mh); mapdc(dc, win, mw, mh);
} }
char *
fstrstr(const char *s, const char *sub) {
size_t len;
for(len = strlen(sub); *s; s++)
if(!fstrncmp(s, sub, len))
return (char *)s;
return NULL;
}
void void
grabkeyboard(void) { grabkeyboard(void) {
int i; int i;
@ -219,7 +223,7 @@ insert(const char *str, ssize_t n) {
if(n > 0) if(n > 0)
memcpy(&text[cursor], str, n); memcpy(&text[cursor], str, n);
cursor += n; cursor += n;
match(n > 0 && text[cursor] == '\0');
match();
} }
void void
@ -233,58 +237,37 @@ keypress(XKeyEvent *ev) {
XConvertCase(ksym, &lower, &upper); XConvertCase(ksym, &lower, &upper);
switch(lower) { switch(lower) {
default:
return;
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_h:
ksym = XK_BackSpace;
break;
case XK_i:
ksym = XK_Tab;
break;
case XK_j:
case XK_m:
ksym = XK_Return;
break;
case XK_k: /* delete right */
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_h: ksym = XK_BackSpace; break;
case XK_i: ksym = XK_Tab; break;
case XK_j: ksym = XK_Return; break;
case XK_m: ksym = XK_Return; break;
case XK_n: ksym = XK_Up; break;
case XK_p: ksym = XK_Down; break;
case XK_k: /* delete right */
text[cursor] = '\0'; text[cursor] = '\0';
match(False);
break;
case XK_n:
ksym = XK_Down;
break;
case XK_p:
ksym = XK_Up;
match();
break; break;
case XK_u: /* delete left */
case XK_u: /* delete left */
insert(NULL, 0 - cursor); insert(NULL, 0 - cursor);
break; break;
case XK_w: /* delete word */
case XK_w: /* delete word */
while(cursor > 0 && text[nextrune(-1)] == ' ') while(cursor > 0 && text[nextrune(-1)] == ' ')
insert(NULL, nextrune(-1) - cursor); insert(NULL, nextrune(-1) - cursor);
while(cursor > 0 && text[nextrune(-1)] != ' ') while(cursor > 0 && text[nextrune(-1)] != ' ')
insert(NULL, nextrune(-1) - cursor); insert(NULL, nextrune(-1) - cursor);
break; break;
case XK_y: /* paste selection */
case XK_y: /* paste selection */
XConvertSelection(dc->dpy, XA_PRIMARY, utf8, utf8, win, CurrentTime); XConvertSelection(dc->dpy, XA_PRIMARY, utf8, utf8, win, CurrentTime);
return; return;
default:
return;
} }
} }
switch(ksym) { switch(ksym) {
@ -296,9 +279,11 @@ keypress(XKeyEvent *ev) {
if(text[cursor] == '\0') if(text[cursor] == '\0')
return; return;
cursor = nextrune(+1); cursor = nextrune(+1);
/* fallthrough */
case XK_BackSpace: case XK_BackSpace:
if(cursor > 0)
insert(NULL, nextrune(-1) - cursor);
if(cursor == 0)
return;
insert(NULL, nextrune(-1) - cursor);
break; break;
case XK_End: case XK_End:
if(text[cursor] != '\0') { if(text[cursor] != '\0') {
@ -330,8 +315,7 @@ keypress(XKeyEvent *ev) {
cursor = nextrune(-1); cursor = nextrune(-1);
break; break;
} }
else if(lines > 0)
return;
/* fallthrough */
case XK_Up: case XK_Up:
if(sel && sel->left && (sel = sel->left)->right == curr) { if(sel && sel->left && (sel = sel->left)->right == curr) {
curr = prev; curr = prev;
@ -352,15 +336,14 @@ keypress(XKeyEvent *ev) {
break; break;
case XK_Return: case XK_Return:
case XK_KP_Enter: case XK_KP_Enter:
fputs((sel && !(ev->state & ShiftMask)) ? sel->text : text, stdout);
puts((sel && !(ev->state & ShiftMask)) ? sel->text : text);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
case XK_Right: case XK_Right:
if(text[cursor] != '\0') { if(text[cursor] != '\0') {
cursor = nextrune(+1); cursor = nextrune(+1);
break; break;
} }
else if(lines > 0)
return;
/* fallthrough */
case XK_Down: case XK_Down:
if(sel && sel->right && (sel = sel->right) == next) { if(sel && sel->right && (sel = sel->right) == next) {
curr = next; curr = next;
@ -372,33 +355,44 @@ keypress(XKeyEvent *ev) {
return; return;
strncpy(text, sel->text, sizeof text); strncpy(text, sel->text, sizeof text);
cursor = strlen(text); cursor = strlen(text);
match(True);
match();
break; break;
} }
drawmenu(); drawmenu();
} }
void void
match(Bool sub) {
size_t len = strlen(text);
Item *lexact, *lprefix, *lsubstr, *exactend, *prefixend, *substrend;
Item *item, *lnext;
lexact = lprefix = lsubstr = exactend = prefixend = substrend = NULL;
for(item = sub ? matches : items; item && item->text; item = lnext) {
lnext = sub ? item->right : item + 1;
if(!fstrncmp(text, item->text, len + 1))
appenditem(item, &lexact, &exactend);
else if(!fstrncmp(text, item->text, len))
match(void) {
static char **tokv = NULL;
static int tokn = 0;
char buf[sizeof text], *s;
int i, tokc = 0;
size_t len;
Item *item, *lprefix, *lsubstr, *prefixend, *substrend;
strcpy(buf, text);
for(s = strtok(buf, " "); s; tokv[tokc-1] = s, s = strtok(NULL, " "))
if(++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv)))
eprintf("cannot realloc %u bytes\n", tokn * sizeof *tokv);
len = tokc ? strlen(tokv[0]) : 0;
matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL;
for(item = items; item && item->text; item++) {
for(i = 0; i < tokc; i++)
if(!fstrstr(item->text, tokv[i]))
break;
if(i != tokc)
continue;
if(!tokc || !fstrncmp(tokv[0], item->text, len+1))
appenditem(item, &matches, &matchend);
else if(!fstrncmp(tokv[0], item->text, len))
appenditem(item, &lprefix, &prefixend); appenditem(item, &lprefix, &prefixend);
else if(fstrstr(item->text, text))
else
appenditem(item, &lsubstr, &substrend); appenditem(item, &lsubstr, &substrend);
} }
matches = lexact;
matchend = exactend;
if(lprefix) { if(lprefix) {
if(matchend) {
if(matches) {
matchend->right = lprefix; matchend->right = lprefix;
lprefix->left = matchend; lprefix->left = matchend;
} }
@ -407,7 +401,7 @@ match(Bool sub) {
matchend = prefixend; matchend = prefixend;
} }
if(lsubstr) { if(lsubstr) {
if(matchend) {
if(matches) {
matchend->right = lsubstr; matchend->right = lsubstr;
lsubstr->left = matchend; lsubstr->left = matchend;
} }
@ -460,6 +454,7 @@ readstdin(void) {
if(items) if(items)
items[i].text = NULL; items[i].text = NULL;
inputw = maxstr ? textw(dc, maxstr) : 0; inputw = maxstr ? textw(dc, maxstr) : 0;
lines = MIN(lines, i);
} }
void void
@ -470,7 +465,7 @@ run(void) {
switch(ev.type) { switch(ev.type) {
case Expose: case Expose:
if(ev.xexpose.count == 0) if(ev.xexpose.count == 0)
drawmenu();
mapdc(dc, win, mw, mh);
break; break;
case KeyPress: case KeyPress:
keypress(&ev.xkey); keypress(&ev.xkey);
@ -490,7 +485,7 @@ void
setup(void) { setup(void) {
int x, y, screen = DefaultScreen(dc->dpy); int x, y, screen = DefaultScreen(dc->dpy);
Window root = RootWindow(dc->dpy, screen); Window root = RootWindow(dc->dpy, screen);
XSetWindowAttributes wa;
XSetWindowAttributes swa;
#ifdef XINERAMA #ifdef XINERAMA
int n; int n;
XineramaScreenInfo *info; XineramaScreenInfo *info;
@ -511,9 +506,14 @@ setup(void) {
if((info = XineramaQueryScreens(dc->dpy, &n))) { if((info = XineramaQueryScreens(dc->dpy, &n))) {
int i, di; int i, di;
unsigned int du; unsigned int du;
Window dw;
Window w, dw;
XWindowAttributes wa;
XQueryPointer(dc->dpy, root, &dw, &dw, &x, &y, &di, &di, &du);
XGetInputFocus(dc->dpy, &w, &di);
if(w != root && w != PointerRoot && w != None && XGetWindowAttributes(dc->dpy, w, &wa))
XTranslateCoordinates(dc->dpy, w, root, wa.x, wa.y, &x, &y, &dw);
else
XQueryPointer(dc->dpy, root, &dw, &dw, &x, &y, &di, &di, &du);
for(i = 0; i < n-1; i++) for(i = 0; i < n-1; i++)
if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height)) if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height))
break; break;
@ -531,16 +531,16 @@ setup(void) {
} }
promptw = prompt ? textw(dc, prompt) : 0; promptw = prompt ? textw(dc, prompt) : 0;
inputw = MIN(inputw, mw/3); inputw = MIN(inputw, mw/3);
match(False);
match();
/* menu window */ /* menu window */
wa.override_redirect = True;
wa.background_pixmap = ParentRelative;
wa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
swa.override_redirect = True;
swa.background_pixmap = ParentRelative;
swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
win = XCreateWindow(dc->dpy, root, x, y, mw, mh, 0, win = XCreateWindow(dc->dpy, root, x, y, mw, mh, 0,
DefaultDepth(dc->dpy, screen), CopyFromParent, DefaultDepth(dc->dpy, screen), CopyFromParent,
DefaultVisual(dc->dpy, screen), DefaultVisual(dc->dpy, screen),
CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
CWOverrideRedirect | CWBackPixmap | CWEventMask, &swa);
XMapRaised(dc->dpy, win); XMapRaised(dc->dpy, win);
resizedc(dc, mw, mh); resizedc(dc, mw, mh);


+ 1
- 1
dmenu_run View File

@ -6,4 +6,4 @@ CACHE=${XDG_CACHE_HOME:-"$HOME/.cache"}/dmenu_run
mkdir -p "`dirname "$CACHE"`" && lsx $PATH | sort -u > "$CACHE" mkdir -p "`dirname "$CACHE"`" && lsx $PATH | sort -u > "$CACHE"
fi fi
) )
cmd=`dmenu "$@" < "$CACHE"` && exec $cmd
cmd=`dmenu "$@" < "$CACHE"` && exec sh -c "$cmd"

+ 11
- 11
draw.c View File

@ -96,7 +96,7 @@ initdc(void) {
DC *dc; DC *dc;
if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
fprintf(stderr, "no locale support\n");
fputs("no locale support\n", stderr);
if(!(dc = calloc(1, sizeof *dc))) if(!(dc = calloc(1, sizeof *dc)))
eprintf("cannot malloc %u bytes:", sizeof *dc); eprintf("cannot malloc %u bytes:", sizeof *dc);
if(!(dc->dpy = XOpenDisplay(NULL))) if(!(dc->dpy = XOpenDisplay(NULL)))
@ -120,28 +120,28 @@ initfont(DC *dc, const char *fontstr) {
Bool Bool
loadfont(DC *dc, const char *fontstr) { loadfont(DC *dc, const char *fontstr) {
char *def, **missing;
char *def, **missing, **names;
int i, n; int i, n;
XFontStruct **xfonts;
if(!*fontstr) if(!*fontstr)
return False; return False;
if((dc->font.set = XCreateFontSet(dc->dpy, fontstr, &missing, &n, &def))) { if((dc->font.set = XCreateFontSet(dc->dpy, fontstr, &missing, &n, &def))) {
char **names;
XFontStruct **xfonts;
n = XFontsOfFontSet(dc->font.set, &xfonts, &names); n = XFontsOfFontSet(dc->font.set, &xfonts, &names);
for(i = dc->font.ascent = dc->font.descent = 0; i < n; i++) {
dc->font.ascent = MAX(dc->font.ascent, xfonts[i]->ascent);
for(i = 0; i < n; i++) {
dc->font.ascent = MAX(dc->font.ascent, xfonts[i]->ascent);
dc->font.descent = MAX(dc->font.descent, xfonts[i]->descent); dc->font.descent = MAX(dc->font.descent, xfonts[i]->descent);
dc->font.width = MAX(dc->font.width, xfonts[i]->max_bounds.width);
} }
} }
else if((dc->font.xfont = XLoadQueryFont(dc->dpy, fontstr))) { else if((dc->font.xfont = XLoadQueryFont(dc->dpy, fontstr))) {
dc->font.ascent = dc->font.xfont->ascent;
dc->font.ascent = dc->font.xfont->ascent;
dc->font.descent = dc->font.xfont->descent; dc->font.descent = dc->font.xfont->descent;
dc->font.width = dc->font.xfont->max_bounds.width;
} }
if(missing) if(missing)
XFreeStringList(missing); XFreeStringList(missing);
return (dc->font.set || dc->font.xfont);
return dc->font.set || dc->font.xfont;
} }
void void
@ -154,10 +154,10 @@ resizedc(DC *dc, unsigned int w, unsigned int h) {
if(dc->canvas) if(dc->canvas)
XFreePixmap(dc->dpy, dc->canvas); XFreePixmap(dc->dpy, dc->canvas);
dc->canvas = XCreatePixmap(dc->dpy, DefaultRootWindow(dc->dpy), w, h,
DefaultDepth(dc->dpy, DefaultScreen(dc->dpy)));
dc->w = w; dc->w = w;
dc->h = h; dc->h = h;
dc->canvas = XCreatePixmap(dc->dpy, DefaultRootWindow(dc->dpy), w, h,
DefaultDepth(dc->dpy, DefaultScreen(dc->dpy)));
} }
int int


+ 1
- 0
draw.h View File

@ -15,6 +15,7 @@ typedef struct {
int ascent; int ascent;
int descent; int descent;
int height; int height;
int width;
XFontSet set; XFontSet set;
XFontStruct *xfont; XFontStruct *xfont;
} font; } font;


+ 2
- 2
lsx.c View File

@ -1,8 +1,8 @@
/* See LICENSE file for copyright and license details. */ /* See LICENSE file for copyright and license details. */
#include <dirent.h> #include <dirent.h>
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -31,7 +31,7 @@ lsx(const char *dir) {
return; return;
} }
while((d = readdir(dp))) while((d = readdir(dp)))
if(snprintf(buf, sizeof buf, "%s/%s", dir, d->d_name) < sizeof buf
if(snprintf(buf, sizeof buf, "%s/%s", dir, d->d_name) < (int)sizeof buf
&& !stat(buf, &st) && S_ISREG(st.st_mode) && access(buf, X_OK) == 0) && !stat(buf, &st) && S_ISREG(st.st_mode) && access(buf, X_OK) == 0)
puts(d->d_name); puts(d->d_name);
closedir(dp); closedir(dp);


Loading…
Cancel
Save