Compare commits

...

18 Commits
4.3.1 ... 4.4

Author SHA1 Message Date
bae58f61cf add lsx.1 to dist 2011-07-19 21:30:09 +01:00
1636e12210 tweaks 2011-07-17 14:06:53 +01:00
2b92c95230 efficiency tweaks 2011-07-14 20:03:08 +01:00
16a0c0d52a fix extra warning 2011-07-14 20:03:00 +01:00
5867c53390 simpler vline 2011-07-06 13:40:36 +01:00
34a816f87d rebind ^N ^P 2011-07-04 16:55:09 +01:00
0288b576ca include limits.h 2011-06-25 17:02:14 +01:00
59dafc4ad6 make clean lsx 2011-06-23 22:39:20 +01:00
49672e9d05 merge lsx -> default 2011-06-23 20:27:28 +01:00
07d452e0c8 close lsx branch 2011-06-23 20:26:57 +01:00
88d44169e9 lsx: check snprintf 2011-06-23 20:04:50 +01:00
f7cbe710a2 update draw.c 2011-06-18 22:11:19 +01:00
86e9e6f1ec simpler lsx 2011-06-18 07:50:46 +01:00
eadf090413 new dmenu_run 2011-06-13 21:50:31 +01:00
8ec1b41cac add lsx.1 2011-06-13 19:32:45 +01:00
ab3bcac0bf new lsx branch 2011-06-13 19:28:30 +01:00
723cbabc12 add ^M 2011-06-13 19:25:40 +01:00
86775cc44b Added tag 4.3.1 for changeset 34a2d77049a9 2011-05-18 17:01:59 +01:00
11 changed files with 141 additions and 106 deletions

View File

@ -45,3 +45,4 @@ e4c81a78ffbad6ba4d1ad119cc654da6eca63a4c 3.2
379813a051f03a1b20bdbfdc2d2d1d2d794ace48 4.2 379813a051f03a1b20bdbfdc2d2d1d2d794ace48 4.2
abb6579a324fffdf6a23c2fa4c32911277da594a 4.2.1 abb6579a324fffdf6a23c2fa4c32911277da594a 4.2.1
14c79f054bdf43ff3213af8e60a783192e92a018 4.3 14c79f054bdf43ff3213af8e60a783192e92a018 4.3
34a2d77049a95b02f3332a0b88f9370965ebcfad 4.3.1

View File

@ -3,10 +3,10 @@
include config.mk include config.mk
SRC = dmenu.c draw.c SRC = dmenu.c draw.c lsx.c
OBJ = ${SRC:.c=.o} OBJ = ${SRC:.c=.o}
all: options dmenu all: options dmenu lsx
options: options:
@echo dmenu build options: @echo dmenu build options:
@ -20,18 +20,22 @@ options:
${OBJ}: config.mk ${OBJ}: config.mk
dmenu: ${OBJ} dmenu: dmenu.o draw.o
@echo CC -o $@ @echo CC -o $@
@${CC} -o $@ ${OBJ} ${LDFLAGS} @${CC} -o $@ dmenu.o draw.o ${LDFLAGS}
lsx: lsx.o
@echo CC -o $@
@${CC} -o $@ lsx.o ${LDFLAGS}
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_path 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}
@ -39,21 +43,24 @@ dist: clean
install: all install: all
@echo installing executables to ${DESTDIR}${PREFIX}/bin @echo installing executables to ${DESTDIR}${PREFIX}/bin
@mkdir -p ${DESTDIR}${PREFIX}/bin @mkdir -p ${DESTDIR}${PREFIX}/bin
@cp -f dmenu dmenu_path dmenu_run ${DESTDIR}${PREFIX}/bin @cp -f dmenu dmenu_run lsx ${DESTDIR}${PREFIX}/bin
@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu @chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu
@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_path
@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_run @chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_run
@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 @chmod 755 ${DESTDIR}${PREFIX}/bin/lsx
@echo installing manual pages to ${DESTDIR}${MANPREFIX}/man1
@mkdir -p ${DESTDIR}${MANPREFIX}/man1 @mkdir -p ${DESTDIR}${MANPREFIX}/man1
@sed "s/VERSION/${VERSION}/g" < dmenu.1 > ${DESTDIR}${MANPREFIX}/man1/dmenu.1 @sed "s/VERSION/${VERSION}/g" < dmenu.1 > ${DESTDIR}${MANPREFIX}/man1/dmenu.1
@sed "s/VERSION/${VERSION}/g" < lsx.1 > ${DESTDIR}${MANPREFIX}/man1/lsx.1
@chmod 644 ${DESTDIR}${MANPREFIX}/man1/dmenu.1 @chmod 644 ${DESTDIR}${MANPREFIX}/man1/dmenu.1
@chmod 644 ${DESTDIR}${MANPREFIX}/man1/lsx.1
uninstall: uninstall:
@echo removing executables from ${DESTDIR}${PREFIX}/bin @echo removing executables from ${DESTDIR}${PREFIX}/bin
@rm -f ${DESTDIR}${PREFIX}/bin/dmenu @rm -f ${DESTDIR}${PREFIX}/bin/dmenu
@rm -f ${DESTDIR}${PREFIX}/bin/dmenu_path
@rm -f ${DESTDIR}${PREFIX}/bin/dmenu_run @rm -f ${DESTDIR}${PREFIX}/bin/dmenu_run
@rm -f ${DESTDIR}${PREFIX}/bin/lsx
@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
@rm -f ${DESTDIR}${MANPREFIX}/man1/dmenu.1 @rm -f ${DESTDIR}${MANPREFIX}/man1/dmenu.1
@rm -f ${DESTDIR}${MANPREFIX}/man1/lsx.1
.PHONY: all options clean dist install uninstall .PHONY: all options clean dist install uninstall

View File

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

12
dmenu.1
View File

@ -23,12 +23,10 @@ dmenu \- dynamic menu
.RB [ \-v ] .RB [ \-v ]
.P .P
.BR dmenu_run " ..." .BR dmenu_run " ..."
.P
.B dmenu_path
.SH DESCRIPTION .SH DESCRIPTION
.B dmenu .B dmenu
is a dynamic menu for X, originally designed for is a dynamic menu for X, originally designed for
.BR dwm (1). .IR dwm (1).
It manages huge numbers of user\-defined menu items efficiently. It manages huge numbers of user\-defined menu items efficiently.
.P .P
dmenu reads a list of newline\-separated items from stdin and creates a menu. dmenu reads a list of newline\-separated items from stdin and creates a menu.
@ -36,11 +34,8 @@ When the user selects an item or enters any text and presses Return, their
choice is printed to stdout and dmenu terminates. choice is printed to stdout and dmenu terminates.
.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
executes the selected item. executes the selected item.
.P
.B dmenu_path
is a script used by dmenu_run to find and cache a list of executables.
.SH OPTIONS .SH OPTIONS
.TP .TP
.B \-b .B \-b
@ -100,4 +95,5 @@ Exit without selecting an item, returning failure.
.B Ctrl\-y .B Ctrl\-y
Paste the current X selection into the input field. Paste the current X selection into the input field.
.SH SEE ALSO .SH SEE ALSO
.BR dwm (1) .IR dwm (1),
.IR lsx (1)

94
dmenu.c
View File

@ -25,8 +25,8 @@ 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);
@ -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,7 +115,7 @@ main(int argc, char *argv[]) {
setup(); setup();
run(); run();
return EXIT_FAILURE; /* should not reach */ return EXIT_FAILURE; /* unreachable */
} }
void void
@ -121,6 +124,7 @@ appenditem(Item *item, Item **list, Item **last) {
*list = item; *list = item;
else else
(*last)->right = item; (*last)->right = 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;
@ -233,45 +237,23 @@ keypress(XKeyEvent *ev) {
XConvertCase(ksym, &lower, &upper); XConvertCase(ksym, &lower, &upper);
switch(lower) { switch(lower) {
default: case XK_a: ksym = XK_Home; break;
return; case XK_b: ksym = XK_Left; break;
case XK_a: case XK_c: ksym = XK_Escape; break;
ksym = XK_Home; case XK_d: ksym = XK_Delete; break;
break; case XK_e: ksym = XK_End; break;
case XK_b: case XK_f: ksym = XK_Right; break;
ksym = XK_Left; case XK_h: ksym = XK_BackSpace; break;
break; case XK_i: ksym = XK_Tab; break;
case XK_c: case XK_j: ksym = XK_Return; break;
ksym = XK_Escape; case XK_m: ksym = XK_Return; break;
break; case XK_n: ksym = XK_Up; break;
case XK_d: case XK_p: ksym = XK_Down; break;
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_k: /* delete right */ case XK_k: /* delete right */
text[cursor] = '\0'; text[cursor] = '\0';
match(False); match(False);
break; break;
case XK_n:
ksym = XK_Down;
break;
case XK_p:
ksym = XK_Up;
break;
case XK_u: /* delete left */ case XK_u: /* delete left */
insert(NULL, 0 - cursor); insert(NULL, 0 - cursor);
break; break;
@ -284,6 +266,8 @@ keypress(XKeyEvent *ev) {
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) {
@ -295,8 +279,10 @@ 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) if(cursor == 0)
return;
insert(NULL, nextrune(-1) - cursor); insert(NULL, nextrune(-1) - cursor);
break; break;
case XK_End: case XK_End:
@ -329,8 +315,7 @@ keypress(XKeyEvent *ev) {
cursor = nextrune(-1); cursor = nextrune(-1);
break; break;
} }
else if(lines > 0) /* fallthrough */
return;
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;
@ -351,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) /* fallthrough */
return;
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;
@ -469,7 +453,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);

View File

@ -1,9 +0,0 @@
#!/bin/sh
CACHE=$HOME/.dmenu_cache
IFS=:
if ! test -f "$CACHE" || find $PATH -type d -newer "$CACHE" | grep -q .; then
find $PATH ! -type d \( -perm -1 -o -perm -10 -o -perm -100 \) | sed 's/.*\///' | sort -u > "$CACHE"
fi
cat "$CACHE"

View File

@ -1,2 +1,9 @@
#!/bin/sh #!/bin/sh
exe=`dmenu_path | dmenu ${1+"$@"}` && exec $exe CACHE=${XDG_CACHE_HOME:-"$HOME/.cache"}/dmenu_run
(
IFS=:
if test "`ls -dt $PATH "$CACHE" 2> /dev/null | sed 1q`" != "$CACHE"; then
mkdir -p "`dirname "$CACHE"`" && lsx $PATH | sort -u > "$CACHE"
fi
)
cmd=`dmenu "$@" < "$CACHE"` && exec $cmd

29
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,24 +120,23 @@ 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 = 1;
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++) { else if((dc->font.xfont = XLoadQueryFont(dc->dpy, fontstr)))
xfonts = &dc->font.xfont;
else
n = 0;
for(i = 0; i < n; i++) {
dc->font.ascent = MAX(dc->font.ascent, xfonts[i]->ascent); 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))) {
dc->font.ascent = dc->font.xfont->ascent;
dc->font.descent = dc->font.xfont->descent;
} }
if(missing) if(missing)
XFreeStringList(missing); XFreeStringList(missing);
@ -154,10 +153,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
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;

11
lsx.1 Normal file
View File

@ -0,0 +1,11 @@
.TH LSX 1 dmenu\-VERSION
.SH NAME
lsx \- list executables
.SH SYNOPSIS
.B lsx
.RI [ directory ...]
.SH DESCRIPTION
.B lsx
lists the executables in each
.IR directory .
If none are given the current working directory is used.

38
lsx.c Normal file
View File

@ -0,0 +1,38 @@
/* See LICENSE file for copyright and license details. */
#include <dirent.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
static void lsx(const char *dir);
int
main(int argc, char *argv[]) {
int i;
if(argc < 2)
lsx(".");
else for(i = 1; i < argc; i++)
lsx(argv[i]);
return EXIT_SUCCESS;
}
void
lsx(const char *dir) {
char buf[PATH_MAX];
struct dirent *d;
struct stat st;
DIR *dp;
if(!(dp = opendir(dir))) {
perror(dir);
return;
}
while((d = readdir(dp)))
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)
puts(d->d_name);
closedir(dp);
}