Compare commits

...

84 Commits
0.2 ... 1.2

Author SHA1 Message Date
63be0ee22a small change 2006-10-06 12:40:49 +02:00
ca973eb64e changing version info 2006-10-06 12:39:06 +02:00
5fd7af18c6 removed useless newlines 2006-10-06 11:52:57 +02:00
02238725f6 small update to man page (backported) 2006-09-26 17:51:22 +02:00
2d5afd7c01 Added tag 1.1 for changeset e8c1e9733752db12f2dbd1fa93c46f5806242ba9 2006-09-26 17:39:04 +02:00
f7615e220e updated README 2006-09-26 14:31:42 +02:00
e7ecae0d58 removed crap from Makefile 2006-09-26 14:30:48 +02:00
b661ca75de error handling 2006-09-26 13:45:41 +02:00
c02da9f87e foo 2006-09-26 13:41:51 +02:00
14133be5bd reverting 2006-09-26 13:39:00 +02:00
3b590beda2 added fallback to color initialization 2006-09-26 13:37:36 +02:00
5c0d28e4ff removed config.h stuff, made dwm configurable due to command line options 2006-09-26 13:20:47 +02:00
e0fe9f2fca uriel didn't understood dmenu code, he broke nearly everything 2006-09-26 08:47:10 +02:00
c9465859a6 applied a change made by Uriel to dmenu (though I didn't applied everything) 2006-09-26 08:43:41 +02:00
1716159e05 applied something similiar to Jukkas patch 2006-09-25 08:29:20 +02:00
11b6401668 Added tag 1.0 for changeset 9e11140d4cc3eecac3b0ab752f91528fd5e04be8 2006-09-16 11:20:54 +02:00
81bcf078f6 made function signatures more consistent to my coding style 2006-09-12 10:59:00 +02:00
0e5f467aa8 commented dmenu 2006-09-11 13:18:09 +02:00
c51406b279 Added tag 0.9 for changeset d046c818ea467555cc338751c9bf3024609f1f12 2006-09-08 08:31:19 +02:00
32f7fe4835 implemented early keyboard grab for dmenu with a timeout for stdin data writers to prevent endless grabbings of the keyboard 2006-09-08 07:33:20 +02:00
0fa5a339ff new version of dmenu 2006-09-07 19:12:04 +02:00
358f078c0b another fix 2006-09-07 09:40:09 +02:00
1f207893e6 made dmenu.1 also concise 2006-09-07 09:36:53 +02:00
1c5be1c553 Added tag 0.8 for changeset 409667a57221f7e50ba8b5248f638915cd61b366 2006-09-06 10:53:15 +02:00
32ea45084b fixed man page 2006-09-04 19:47:09 +02:00
cc7d863b6e Added tag 0.7 for changeset 5fc20d7158bd16b4d5f8d1c25e177680b6d54252 2006-09-04 17:17:08 +02:00
04eade6a76 small change of main event loop 2006-09-04 07:28:03 +02:00
49ce444d32 updated version 2006-08-28 12:26:25 +02:00
2e9515ee27 Added tag 0.6 for changeset 25f679fb19686140a907684ffcb423b9e9d44b53 2006-08-28 10:20:10 +02:00
d4a4cc1ab8 updated man page 2006-08-28 07:22:38 +02:00
11bda99968 fixed 2006-08-25 18:15:24 +02:00
82b0bc83f8 switching back to a dark color scheme with larger font 2006-08-25 18:03:30 +02:00
bd1172e689 small color fixes 2006-08-25 17:44:40 +02:00
13ef97e65e updated dmenu to borderless drawing as well 2006-08-25 14:45:17 +02:00
65be999a3f back to 3 colors 2006-08-25 07:54:20 +02:00
37faefb1aa removed useless call 2006-08-24 12:04:41 +02:00
18ec376aa9 fixed minor bug 2006-08-24 12:03:40 +02:00
6c1e46654d small color change 2006-08-24 11:57:58 +02:00
e980c7ff18 migrated dmenu to use 4 instead of 3 colors 2006-08-24 11:47:08 +02:00
7848b53dc3 Added tag 0.5 for changeset 4a0ecd881c4fc15de4a0bebd79308b064be020ef 2006-08-24 10:22:51 +02:00
865c938856 prepared dmenu-0.5 2006-08-24 10:22:30 +02:00
30d72e5f87 removed unnecessary Xlib call 2006-08-24 09:27:01 +02:00
0ffd139f2c sanitizing my colorscheme 2006-08-23 19:05:20 +02:00
86512ce930 back to terminus font 2006-08-23 18:55:48 +02:00
d3206194c1 font fix 2006-08-22 10:01:45 +02:00
8148b515a1 fixed 2006-08-22 09:49:56 +02:00
35210e3998 applied OpenBSD changes.. 2006-08-21 17:45:46 +02:00
df85dd743c renamed bad_malloc into badmalloc as well 2006-08-21 07:34:16 +02:00
d9f6fa426b small changes in dmenu.1 2006-08-21 07:31:33 +02:00
bbb2cc2a72 fixed a typo in config.mk, fixed cleanup code in dmenu (now frees all allocated stuff) 2006-08-16 19:25:04 +02:00
02ddc93c94 applied sanders patch 2006-08-16 12:37:01 +02:00
0faf441367 applied sanders Makefile patch 2006-08-16 08:57:10 +02:00
be6b534520 fixed the same issue in dmenu 2006-08-15 16:56:55 +02:00
db76b0f9a5 Added tag 0.4 for changeset 7acf0dde1120542917bae12e0e42293f9d2cc899 2006-08-15 10:39:26 +02:00
26fc52fcf6 removed finished message 2006-08-14 16:11:38 +02:00
6a26e97f74 fixed string cutting 2006-08-14 10:56:57 +02:00
0e21ef5f37 fixed string cutting 2006-08-14 08:52:28 +02:00
2f3068fb77 added comment 2006-08-14 08:44:54 +02:00
b7f8911455 applied Sanders LD patch 2006-08-14 08:42:23 +02:00
35a06ccd2e applied my new color scheme 2006-08-11 18:12:07 +02:00
67649463c8 simplified drawborder 2006-08-11 11:52:34 +02:00
d1415ea497 Added tag 0.3 for changeset d352e9dc112ee96aa5cad961a0ed880ae9ce7276 2006-08-10 15:19:03 +02:00
c6113a3b27 readded border colors, this sucks least 2006-08-10 11:13:21 +02:00
dd902868df drawing border around sel item 2006-08-10 11:07:06 +02:00
4318bf2905 removed unnecessary border color 2006-08-10 10:28:58 +02:00
25f71b3829 swapping my default colors 2006-08-10 10:21:50 +02:00
0af369ba65 added uppercase chars for C-u and C-h as well 2006-08-10 10:10:32 +02:00
e4fbc43253 removed C-[ from source and man page 2006-08-10 10:09:44 +02:00
66f2a93eaa removed control sequences which actually aren't implemented anymore (only the real unix control sequences are implemented) 2006-08-09 18:45:32 +02:00
a381b3a819 fixes to README 2006-08-08 17:14:35 +02:00
2a4b146fc4 default colors are best 2006-08-08 12:47:58 +02:00
84d7f7bccf noborder 2006-08-08 11:47:58 +02:00
00dce8cc39 dito 2006-08-08 11:18:23 +02:00
170b977288 using a better colorscheme 2006-08-08 11:07:12 +02:00
366b2afd6c removed unnecessary typedef 2006-08-07 17:17:27 +02:00
4e009770d6 made dmenu(1) more dwm(1) alike 2006-08-07 14:07:04 +02:00
b24aa8312b font size changed as well 2006-08-07 12:21:31 +02:00
5146c3f27f appliead Sanders manpage/Makefile pacth 2006-08-07 11:58:23 +02:00
6a332a043a fixed dmenu.1 version info 2006-08-07 11:11:17 +02:00
9d574f5ebe settle with grey 2006-08-07 11:10:05 +02:00
1fb8a6b898 next version is 0.3 2006-08-07 10:32:18 +02:00
7fb4c2b818 also made my colors tasting better with my overall colorscheme 2006-08-07 10:28:42 +02:00
f3a60b583f next attempt for bright background switch 2006-08-07 09:40:28 +02:00
48e2ce8709 Added tag 0.2 for changeset 656be0f47df545dfdd2e1e0663663b8b1b26f031 2006-08-07 08:52:37 +02:00
11 changed files with 228 additions and 242 deletions

10
.hgtags
View File

@ -1 +1,11 @@
fcc8a282cb52c6a9343b461026b386825590cd31 0.1 fcc8a282cb52c6a9343b461026b386825590cd31 0.1
656be0f47df545dfdd2e1e0663663b8b1b26f031 0.2
d352e9dc112ee96aa5cad961a0ed880ae9ce7276 0.3
7acf0dde1120542917bae12e0e42293f9d2cc899 0.4
4a0ecd881c4fc15de4a0bebd79308b064be020ef 0.5
25f679fb19686140a907684ffcb423b9e9d44b53 0.6
5fc20d7158bd16b4d5f8d1c25e177680b6d54252 0.7
409667a57221f7e50ba8b5248f638915cd61b366 0.8
d046c818ea467555cc338751c9bf3024609f1f12 0.9
9e11140d4cc3eecac3b0ab752f91528fd5e04be8 1.0
e8c1e9733752db12f2dbd1fa93c46f5806242ba9 1.1

View File

@ -7,27 +7,23 @@ SRC = draw.c main.c util.c
OBJ = ${SRC:.c=.o} OBJ = ${SRC:.c=.o}
all: options dmenu all: options dmenu
@echo finished
options: options:
@echo dmenu build options: @echo dmenu build options:
@echo "CFLAGS = ${CFLAGS}" @echo "CFLAGS = ${CFLAGS}"
@echo "LDFLAGS = ${LDFLAGS}" @echo "LDFLAGS = ${LDFLAGS}"
@echo "CC = ${CC}" @echo "CC = ${CC}"
@echo "LD = ${LD}"
.c.o: .c.o:
@echo CC $< @echo CC $<
@${CC} -c ${CFLAGS} $< @${CC} -c ${CFLAGS} $<
${OBJ}: dmenu.h config.h ${OBJ}: dmenu.h config.mk
config.h:
@echo creating $@ from config.default.h
@cp config.default.h $@
dmenu: ${OBJ} dmenu: ${OBJ}
@echo LD $@ @echo LD $@
@${CC} -o $@ ${OBJ} ${LDFLAGS} @${LD} -o $@ ${OBJ} ${LDFLAGS}
@strip $@ @strip $@
clean: clean:
@ -37,8 +33,7 @@ clean:
dist: clean dist: clean
@echo creating dist tarball @echo creating dist tarball
@mkdir -p dmenu-${VERSION} @mkdir -p dmenu-${VERSION}
@cp -R LICENSE Makefile README config.*.h config.mk \ @cp -R LICENSE Makefile README config.mk dmenu.1 dmenu.h ${SRC} dmenu-${VERSION}
dmenu.1 dmenu.h ${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}
@ -50,7 +45,7 @@ install: all
@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu @chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu
@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
@mkdir -p ${DESTDIR}${MANPREFIX}/man1 @mkdir -p ${DESTDIR}${MANPREFIX}/man1
@cp -f dmenu.1 ${DESTDIR}${MANPREFIX}/man1 @sed 's/VERSION/${VERSION}/g' < dmenu.1 > ${DESTDIR}${MANPREFIX}/man1/dmenu.1
@chmod 644 ${DESTDIR}${MANPREFIX}/man1/dmenu.1 @chmod 644 ${DESTDIR}${MANPREFIX}/man1/dmenu.1
uninstall: uninstall:

13
README
View File

@ -1,7 +1,6 @@
dmenu - dynamic menu dmenu - dynamic menu
-------------------- ====================
dwm is a generic, highly customizable, and efficient menu for the dmenu is a generic and efficient menu for X.
X Window System.
Requirements Requirements
@ -11,7 +10,7 @@ In order to build dmenu you need the Xlib header files.
Installation Installation
------------ ------------
Edit config.mk to match your local setup (dwm is installed into Edit config.mk to match your local setup (dmenu is installed into
the /usr/local namespace by default). the /usr/local namespace by default).
Afterwards enter the following command to build and install dmenu (if Afterwards enter the following command to build and install dmenu (if
@ -23,9 +22,3 @@ necessary as root):
Running dmenu Running dmenu
------------- -------------
See the man page for details. See the man page for details.
Configuration
-------------
The configuration of dmenu is done by creating a custom config.h
and (re)compiling the source code.

View File

@ -1,9 +0,0 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#define FONT "-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*"
#define BGCOLOR "#0a2c2d"
#define FGCOLOR "#ddeeee"
#define BORDERCOLOR "#176164"

View File

@ -1,9 +0,0 @@
/*
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#define FONT "fixed"
#define BGCOLOR "#666699"
#define FGCOLOR "#eeeeee"
#define BORDERCOLOR "#9999CC"

View File

@ -1,5 +1,5 @@
# dmenu version # dmenu version
VERSION = 0.2 VERSION = 1.2
# Customize below to fit your system # Customize below to fit your system
@ -11,7 +11,7 @@ X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib X11LIB = /usr/X11R6/lib
# includes and libs # includes and libs
INCS = -I/usr/lib -I${X11INC} INCS = -I. -I/usr/include -I${X11INC}
LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 LIBS = -L/usr/lib -lc -L${X11LIB} -lX11
# flags # flags
@ -20,5 +20,6 @@ LDFLAGS = ${LIBS}
#CFLAGS = -g -Wall -O2 ${INCS} -DVERSION=\"${VERSION}\" #CFLAGS = -g -Wall -O2 ${INCS} -DVERSION=\"${VERSION}\"
#LDFLAGS = -g ${LIBS} #LDFLAGS = -g ${LIBS}
# compiler # compiler and linker
CC = cc CC = cc
LD = ${CC}

113
dmenu.1
View File

@ -1,65 +1,80 @@
.TH DMENU 1 d-0.0 .TH DMENU 1 dmenu-VERSION
.SH NAME .SH NAME
dmenu \- dynamic menu dmenu \- dynamic menu
.SH SYNOPSIS .SH SYNOPSIS
.B dmenu .B dmenu
.RB [ \-font " <name>"]
.RB [ \-normbg " <color>"]
.RB [ \-normfg " <color>"]
.RB [ \-selbg " <color>"]
.RB [ \-selfg " <color>"]
.RB [ \-t " <seconds>"]
.RB [ \-v ] .RB [ \-v ]
.SH DESCRIPTION .SH DESCRIPTION
.SS Overview .SS Overview
.B dmenu dmenu is a generic menu for X, originally designed for
is a generic, highly customizable, and efficient menu for the X Window System,
originally designed for
.BR dwm (1). .BR dwm (1).
It supports arbitrary, user defined menu contents. It manages huge amounts (up to 10.000 and more) of user defined menu items
efficiently.
.SS Options .SS Options
.TP .TP
.B \-font <name>
defines the font.
.TP
.B \-normbg <color>
defines the normal background color (#RGB, #RRGGBB, and color names are supported).
.TP
.B \-normfg <color>
defines the normal foreground color (#RGB, #RRGGBB, and color names are supported).
.TP
.B \-selbg <color>
defines the selected background color (#RGB, #RRGGBB, and color names are supported).
.TP
.B \-selfg <color>
defines the selected foreground color (#RGB, #RRGGBB, and color names are supported).
.TP
.B \-t <seconds>
defines the seconds to wait for standard input, before exiting (default is 3).
.TP
.B \-v .B \-v
prints version information to stdout, then exits. prints version information to standard output, then exits.
.SS Usage .SH USAGE
.B dmenu dmenu reads a list of newline-separated items from standard input and creates a
reads a list of newline-separated items from stdin and creates a menu. menu. When the user selects an item or enters any text and presses Return, his
When the user selects an item or enters any text and presses Enter, his choice choice is printed to standard output and dmenu terminates.
is printed to stdout and .P
.B dmenu dmenu is completely controlled by the keyboard. The following keys are recognized:
terminates. .TP
.SS Keyboard Control .B Any printable character
.B dmenu Appends the character to the text in the input field. This works as a filter:
is completely controlled by the keyboard. The following keys are recognized:
.TP 2
Any printable character
appends the character to the text in the input field. This works as a filter:
only items containing this text will be displayed. only items containing this text will be displayed.
.TP 2 .TP
Left/Right (Control-p/Control-n) .B Left/Right
select the previous/next item. Select the previous/next item.
.TP 2 .TP
Tab (Control-i) .B Tab
copy the selected item to the input field. Copy the selected item to the input field.
.TP 2 .TP
Enter (Control-j) .B Return
confirm selection and quit (print the selected item to stdout). Confirm selection and quit (print the selected item to standard output). Returns
.TP 2
Shift-Enter (Shift-Control-j)
confirm selection and quit (print the text in the input field to stdout).
.TP 2
Escape (Control-[)
quit without selecting an item.
.TP 2
Backspace (Control-h)
remove enough characters from the input field to change its filtering effect.
.TP 2
Control-u
remove all characters from the input field.
.SS Exit codes
.B dmenu
returns
.B 0 .B 0
if Enter is pressed on termination, on termination.
.TP
.B Shift-Return
Confirm selection and quit (print the text in the input field to standard output).
Returns
.B 0
on termination.
.TP
.B Escape
Quit without selecting an item. Returns
.B 1 .B 1
if Escape is pressed. on termination.
.SH CUSTOMIZATION .TP
.B dmenu .B Backspace (Control-h)
is customized by creating a custom config.h and (re)compiling the source Remove enough characters from the input field to change its filtering effect.
code. This keeps it fast, secure and simple. .TP
.B Control-u
Remove all characters from the input field.
.SH SEE ALSO .SH SEE ALSO
.BR dwm (1) .BR dwm (1)

39
dmenu.h
View File

@ -1,15 +1,20 @@
/* /* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#include "config.h"
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xlocale.h> #include <X11/Xlocale.h>
#define FONT "fixed"
#define NORMBGCOLOR "#333366"
#define NORMFGCOLOR "#cccccc"
#define SELBGCOLOR "#666699"
#define SELFGCOLOR "#eeeeee"
#define SPACE 30 /* px */ #define SPACE 30 /* px */
typedef struct Brush Brush; /* color */
enum { ColFG, ColBG, ColLast };
typedef struct DC DC; typedef struct DC DC;
typedef struct Fnt Fnt; typedef struct Fnt Fnt;
@ -21,27 +26,27 @@ struct Fnt {
int height; int height;
}; };
struct DC { /* draw context */ struct DC {
int x, y, w, h; int x, y, w, h;
unsigned long bg; unsigned long norm[ColLast];
unsigned long fg; unsigned long sel[ColLast];
unsigned long border;
Drawable drawable; Drawable drawable;
Fnt font; Fnt font;
GC gc; GC gc;
}; }; /* draw context */
extern int screen; extern int screen;
extern Display *dpy; extern Display *dpy;
extern DC dc; extern DC dc; /* global drawing context */
/* draw.c */ /* draw.c */
extern void drawtext(const char *text, Bool invert, Bool border); extern void drawtext(const char *text,
extern unsigned long getcolor(const char *colstr); unsigned long col[ColLast]); /* draws text with the defined color tuple */
extern void setfont(const char *fontstr); extern unsigned long getcolor(const char *colstr); /* returns color of colstr */
extern unsigned int textw(const char *text); extern void setfont(const char *fontstr); /* sets global font */
extern unsigned int textw(const char *text); /* returns width of text in px */
/* util.c */ /* util.c */
extern void *emalloc(unsigned int size); extern void *emalloc(unsigned int size); /* allocates memory, exits on error */
extern void eprint(const char *errstr, ...); extern void eprint(const char *errstr, ...); /* prints errstr and exits with 1 */
extern char *estrdup(const char *str); extern char *estrdup(const char *str); /* duplicates str, exits on allocation error */

78
draw.c
View File

@ -1,5 +1,4 @@
/* /* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#include "dmenu.h" #include "dmenu.h"
@ -9,29 +8,8 @@
/* static */ /* static */
static void
drawborder(void)
{
XPoint points[5];
XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
XSetForeground(dpy, dc.gc, dc.border);
points[0].x = dc.x;
points[0].y = dc.y;
points[1].x = dc.w - 1;
points[1].y = 0;
points[2].x = 0;
points[2].y = dc.h - 1;
points[3].x = -(dc.w - 1);
points[3].y = 0;
points[4].x = 0;
points[4].y = -(dc.h - 1);
XDrawLines(dpy, dc.drawable, dc.gc, points, 5, CoordModePrevious);
}
static unsigned int static unsigned int
textnw(const char *text, unsigned int len) textnw(const char *text, unsigned int len) {
{
XRectangle r; XRectangle r;
if(dc.font.set) { if(dc.font.set) {
@ -44,68 +22,64 @@ textnw(const char *text, unsigned int len)
/* extern */ /* extern */
void void
drawtext(const char *text, Bool invert, Bool border) drawtext(const char *text, unsigned long col[ColLast]) {
{
int x, y, w, h; int x, y, w, h;
static char buf[256]; static char buf[256];
unsigned int len; unsigned int len, olen;
XGCValues gcv; XGCValues gcv;
XRectangle r = { dc.x, dc.y, dc.w, dc.h }; XRectangle r = { dc.x, dc.y, dc.w, dc.h };
XSetForeground(dpy, dc.gc, invert ? dc.fg : dc.bg); XSetForeground(dpy, dc.gc, col[ColBG]);
XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
w = 0;
if(border)
drawborder();
if(!text) if(!text)
return; return;
w = 0;
len = strlen(text); olen = len = strlen(text);
if(len >= sizeof(buf)) if(len >= sizeof(buf))
len = sizeof(buf) - 1; len = sizeof(buf) - 1;
memcpy(buf, text, len); memcpy(buf, text, len);
buf[len] = 0; buf[len] = 0;
h = dc.font.ascent + dc.font.descent; h = dc.font.ascent + dc.font.descent;
y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
x = dc.x + (h / 2); x = dc.x + (h / 2);
/* shorten text if necessary */ /* shorten text if necessary */
while(len && (w = textnw(buf, len)) > dc.w - h) while(len && (w = textnw(buf, len)) > dc.w - h)
buf[--len] = 0; buf[--len] = 0;
if(len < olen) {
if(len > 1)
buf[len - 1] = '.';
if(len > 2)
buf[len - 2] = '.';
if(len > 3)
buf[len - 3] = '.';
}
if(w > dc.w) if(w > dc.w)
return; /* too long */ return; /* too long */
gcv.foreground = col[ColFG];
gcv.foreground = invert ? dc.bg : dc.fg;
gcv.background = invert ? dc.fg : dc.bg;
if(dc.font.set) { if(dc.font.set) {
XChangeGC(dpy, dc.gc, GCForeground | GCBackground, &gcv); XChangeGC(dpy, dc.gc, GCForeground, &gcv);
XmbDrawImageString(dpy, dc.drawable, dc.font.set, dc.gc, XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc,
x, y, buf, len); x, y, buf, len);
} }
else { else {
gcv.font = dc.font.xfont->fid; gcv.font = dc.font.xfont->fid;
XChangeGC(dpy, dc.gc, GCForeground | GCBackground | GCFont, &gcv); XChangeGC(dpy, dc.gc, GCForeground | GCFont, &gcv);
XDrawImageString(dpy, dc.drawable, dc.gc, x, y, buf, len); XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
} }
} }
unsigned long unsigned long
getcolor(const char *colstr) getcolor(const char *colstr) {
{
Colormap cmap = DefaultColormap(dpy, screen); Colormap cmap = DefaultColormap(dpy, screen);
XColor color; XColor color;
XAllocNamedColor(dpy, cmap, colstr, &color, &color); if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
eprint("error, cannot allocate color '%s'\n", colstr);
return color.pixel; return color.pixel;
} }
void void
setfont(const char *fontstr) setfont(const char *fontstr) {
{
char **missing, *def; char **missing, *def;
int i, n; int i, n;
@ -125,7 +99,6 @@ setfont(const char *fontstr)
XFontSetExtents *font_extents; XFontSetExtents *font_extents;
XFontStruct **xfonts; XFontStruct **xfonts;
char **font_names; char **font_names;
dc.font.ascent = dc.font.descent = 0; dc.font.ascent = dc.font.descent = 0;
font_extents = XExtentsOfFontSet(dc.font.set); font_extents = XExtentsOfFontSet(dc.font.set);
n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
@ -153,7 +126,6 @@ setfont(const char *fontstr)
} }
unsigned int unsigned int
textw(const char *text) textw(const char *text) {
{
return textnw(text, strlen(text)) + dc.font.height; return textnw(text, strlen(text)) + dc.font.height;
} }

148
main.c
View File

@ -1,9 +1,7 @@
/* /* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* (C)opyright MMVI Sander van Dijk <a dot h dot vandijk at gmail dot com> * (C)opyright MMVI Sander van Dijk <a dot h dot vandijk at gmail dot com>
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#include "dmenu.h" #include "dmenu.h"
#include <ctype.h> #include <ctype.h>
@ -11,6 +9,8 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <X11/cursorfont.h> #include <X11/cursorfont.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <X11/keysym.h> #include <X11/keysym.h>
@ -29,7 +29,7 @@ static int mx, my, mw, mh;
static int ret = 0; static int ret = 0;
static int nitem = 0; static int nitem = 0;
static unsigned int cmdw = 0; static unsigned int cmdw = 0;
static Bool done = False; static Bool running = True;
static Item *allitems = NULL; /* first of all items */ static Item *allitems = NULL; /* first of all items */
static Item *item = NULL; /* first of pattern matching items */ static Item *item = NULL; /* first of pattern matching items */
static Item *sel = NULL; static Item *sel = NULL;
@ -40,13 +40,11 @@ static Window root;
static Window win; static Window win;
static void static void
calcoffsets() calcoffsets(void) {
{
unsigned int tw, w; unsigned int tw, w;
if(!curr) if(!curr)
return; return;
w = cmdw + 2 * SPACE; w = cmdw + 2 * SPACE;
for(next = curr; next; next=next->right) { for(next = curr; next; next=next->right) {
tw = textw(next->text); tw = textw(next->text);
@ -56,7 +54,6 @@ calcoffsets()
if(w > mw) if(w > mw)
break; break;
} }
w = cmdw + 2 * SPACE; w = cmdw + 2 * SPACE;
for(prev = curr; prev && prev->left; prev=prev->left) { for(prev = curr; prev && prev->left; prev=prev->left) {
tw = textw(prev->left->text); tw = textw(prev->left->text);
@ -69,57 +66,49 @@ calcoffsets()
} }
static void static void
drawmenu() drawmenu(void) {
{
Item *i; Item *i;
dc.x = 0; dc.x = 0;
dc.y = 0; dc.y = 0;
dc.w = mw; dc.w = mw;
dc.h = mh; dc.h = mh;
drawtext(NULL, False, False); drawtext(NULL, dc.norm);
/* print command */ /* print command */
if(cmdw && item) if(cmdw && item)
dc.w = cmdw; dc.w = cmdw;
drawtext(text[0] ? text : NULL, False, False); drawtext(text[0] ? text : NULL, dc.norm);
dc.x += cmdw; dc.x += cmdw;
if(curr) { if(curr) {
dc.w = SPACE; dc.w = SPACE;
drawtext((curr && curr->left) ? "<" : NULL, False, False); drawtext((curr && curr->left) ? "<" : NULL, dc.norm);
dc.x += dc.w; dc.x += dc.w;
/* determine maximum items */ /* determine maximum items */
for(i = curr; i != next; i=i->right) { for(i = curr; i != next; i=i->right) {
dc.w = textw(i->text); dc.w = textw(i->text);
if(dc.w > mw / 3) if(dc.w > mw / 3)
dc.w = mw / 3; dc.w = mw / 3;
drawtext(i->text, sel == i, sel == i); drawtext(i->text, (sel == i) ? dc.sel : dc.norm);
dc.x += dc.w; dc.x += dc.w;
} }
dc.x = mw - SPACE; dc.x = mw - SPACE;
dc.w = SPACE; dc.w = SPACE;
drawtext(next ? ">" : NULL, False, False); drawtext(next ? ">" : NULL, dc.norm);
} }
XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, mw, mh, 0, 0); XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, mw, mh, 0, 0);
XFlush(dpy); XFlush(dpy);
} }
static void static void
match(char *pattern) match(char *pattern) {
{
unsigned int plen; unsigned int plen;
Item *i, *j; Item *i, *j;
if(!pattern) if(!pattern)
return; return;
plen = strlen(pattern); plen = strlen(pattern);
item = j = NULL; item = j = NULL;
nitem = 0; nitem = 0;
for(i = allitems; i; i=i->next) for(i = allitems; i; i=i->next)
if(!plen || !strncmp(pattern, i->text, plen)) { if(!plen || !strncmp(pattern, i->text, plen)) {
if(!j) if(!j)
@ -143,14 +132,12 @@ match(char *pattern)
j = i; j = i;
nitem++; nitem++;
} }
curr = prev = next = sel = item; curr = prev = next = sel = item;
calcoffsets(); calcoffsets();
} }
static void static void
kpress(XKeyEvent * e) kpress(XKeyEvent * e) {
{
char buf[32]; char buf[32];
int num, prev_nitem; int num, prev_nitem;
unsigned int i, len; unsigned int i, len;
@ -159,12 +146,10 @@ kpress(XKeyEvent * e)
len = strlen(text); len = strlen(text);
buf[0] = 0; buf[0] = 0;
num = XLookupString(e, buf, sizeof(buf), &ksym, 0); num = XLookupString(e, buf, sizeof(buf), &ksym, 0);
if(IsFunctionKey(ksym) || IsKeypadKey(ksym) if(IsFunctionKey(ksym) || IsKeypadKey(ksym)
|| IsMiscFunctionKey(ksym) || IsPFKey(ksym) || IsMiscFunctionKey(ksym) || IsPFKey(ksym)
|| IsPrivateKeypadKey(ksym)) || IsPrivateKeypadKey(ksym))
return; return;
/* first check if a control mask is omitted */ /* first check if a control mask is omitted */
if(e->state & ControlMask) { if(e->state & ControlMask) {
switch (ksym) { switch (ksym) {
@ -172,18 +157,16 @@ kpress(XKeyEvent * e)
return; return;
break; break;
case XK_h: case XK_h:
case XK_H:
ksym = XK_BackSpace; ksym = XK_BackSpace;
break; break;
case XK_U:
case XK_u: case XK_u:
case XK_U:
text[0] = 0; text[0] = 0;
match(text); match(text);
drawmenu(); drawmenu();
return; return;
break; break;
case XK_bracketleft:
ksym = XK_Escape;
break;
} }
} }
switch(ksym) { switch(ksym) {
@ -212,20 +195,18 @@ kpress(XKeyEvent * e)
} }
break; break;
case XK_Return: case XK_Return:
if(e->state & ShiftMask) { if((e->state & ShiftMask) && text)
if(text)
fprintf(stdout, "%s", text); fprintf(stdout, "%s", text);
}
else if(sel) else if(sel)
fprintf(stdout, "%s", sel->text); fprintf(stdout, "%s", sel->text);
else if(text) else if(text)
fprintf(stdout, "%s", text); fprintf(stdout, "%s", text);
fflush(stdout); fflush(stdout);
done = True; running = False;
break; break;
case XK_Escape: case XK_Escape:
ret = 1; ret = 1;
done = True; running = False;
break; break;
case XK_BackSpace: case XK_BackSpace:
if((i = len)) { if((i = len)) {
@ -251,8 +232,7 @@ kpress(XKeyEvent * e)
} }
static char * static char *
readstdin() readstdin(void) {
{
static char *maxname = NULL; static char *maxname = NULL;
char *p, buf[1024]; char *p, buf[1024];
unsigned int len = 0, max = 0; unsigned int len = 0, max = 0;
@ -268,7 +248,6 @@ readstdin()
maxname = p; maxname = p;
max = len; max = len;
} }
new = emalloc(sizeof(Item)); new = emalloc(sizeof(Item));
new->next = new->left = new->right = NULL; new->next = new->left = new->right = NULL;
new->text = p; new->text = p;
@ -289,61 +268,87 @@ Display *dpy;
DC dc = {0}; DC dc = {0};
int int
main(int argc, char *argv[]) main(int argc, char *argv[]) {
{ char *font = FONT;
char *maxname; char *maxname;
char *normbg = NORMBGCOLOR;
char *normfg = NORMFGCOLOR;
char *selbg = SELBGCOLOR;
char *selfg = SELFGCOLOR;
fd_set rd;
int i;
struct timeval timeout;
Item *itm;
XEvent ev; XEvent ev;
XSetWindowAttributes wa; XSetWindowAttributes wa;
if(argc == 2 && !strncmp("-v", argv[1], 3)) { timeout.tv_usec = 0;
timeout.tv_sec = 3;
/* command line args */
for(i = 1; i < argc; i++)
if(!strncmp(argv[i], "-font", 6))
font = argv[++i];
else if(!strncmp(argv[i], "-normbg", 8))
normbg = argv[++i];
else if(!strncmp(argv[i], "-normfg", 8))
normfg = argv[++i];
else if(!strncmp(argv[i], "-selbg", 7))
selbg = argv[++i];
else if(!strncmp(argv[i], "-selfg", 7))
selfg = argv[++i];
else if(!strncmp(argv[i], "-t", 3))
timeout.tv_sec = atoi(argv[++i]);
else if(!strncmp(argv[i], "-v", 3)) {
fputs("dmenu-"VERSION", (C)opyright MMVI Anselm R. Garbe\n", stdout); fputs("dmenu-"VERSION", (C)opyright MMVI Anselm R. Garbe\n", stdout);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
else if(argc != 1) else
eprint("usage: dmenu [-v]\n"); eprint("usage: dmenu [-font <name>] [-{norm,sel}{bg,fg} <color>] [-t <seconds>] [-v]\n", stdout);
dpy = XOpenDisplay(0); dpy = XOpenDisplay(0);
if(!dpy) if(!dpy)
eprint("dmenu: cannot open display\n"); eprint("dmenu: cannot open display\n");
screen = DefaultScreen(dpy); screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen); root = RootWindow(dpy, screen);
maxname = readstdin(); /* Note, the select() construction allows to grab all keypresses as
* early as possible, to not loose them. But if there is no standard
/* grab as early as possible, but after reading all items!!! */ * input supplied, we will make sure to exit after MAX_WAIT_STDIN
* seconds. This is convenience behavior for rapid typers.
*/
while(XGrabKeyboard(dpy, root, True, GrabModeAsync, while(XGrabKeyboard(dpy, root, True, GrabModeAsync,
GrabModeAsync, CurrentTime) != GrabSuccess) GrabModeAsync, CurrentTime) != GrabSuccess)
usleep(1000); usleep(1000);
FD_ZERO(&rd);
FD_SET(STDIN_FILENO, &rd);
if(select(ConnectionNumber(dpy) + 1, &rd, NULL, NULL, &timeout) < 1)
goto UninitializedEnd;
maxname = readstdin();
/* style */ /* style */
dc.bg = getcolor(BGCOLOR); dc.norm[ColBG] = getcolor(normbg);
dc.fg = getcolor(FGCOLOR); dc.norm[ColFG] = getcolor(normfg);
dc.border = getcolor(BORDERCOLOR); dc.sel[ColBG] = getcolor(selbg);
setfont(FONT); dc.sel[ColFG] = getcolor(selfg);
setfont(font);
/* menu window */
wa.override_redirect = 1; wa.override_redirect = 1;
wa.background_pixmap = ParentRelative; wa.background_pixmap = ParentRelative;
wa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask; wa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask;
mx = my = 0; mx = my = 0;
mw = DisplayWidth(dpy, screen); mw = DisplayWidth(dpy, screen);
mh = dc.font.height + 4; mh = dc.font.height + 2;
win = XCreateWindow(dpy, root, mx, my, mw, mh, 0, win = XCreateWindow(dpy, root, mx, my, mw, mh, 0,
DefaultDepth(dpy, screen), CopyFromParent, DefaultDepth(dpy, screen), CopyFromParent,
DefaultVisual(dpy, screen), DefaultVisual(dpy, screen),
CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
XDefineCursor(dpy, win, XCreateFontCursor(dpy, XC_xterm)); XDefineCursor(dpy, win, XCreateFontCursor(dpy, XC_xterm));
/* pixmap */ /* pixmap */
dc.drawable = XCreatePixmap(dpy, root, mw, mh, DefaultDepth(dpy, screen)); dc.drawable = XCreatePixmap(dpy, root, mw, mh, DefaultDepth(dpy, screen));
dc.gc = XCreateGC(dpy, root, 0, 0); dc.gc = XCreateGC(dpy, root, 0, 0);
XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
if(maxname) if(maxname)
cmdw = textw(maxname); cmdw = textw(maxname);
if(cmdw > mw / 3) if(cmdw > mw / 3)
cmdw = mw / 3; cmdw = mw / 3;
text[0] = 0; text[0] = 0;
match(text); match(text);
XMapRaised(dpy, win); XMapRaised(dpy, win);
@ -351,8 +356,10 @@ main(int argc, char *argv[])
XSync(dpy, False); XSync(dpy, False);
/* main event loop */ /* main event loop */
while(!done && !XNextEvent(dpy, &ev)) { while(running && !XNextEvent(dpy, &ev)) {
switch (ev.type) { switch (ev.type) {
default: /* ignore all crap */
break;
case KeyPress: case KeyPress:
kpress(&ev.xkey); kpress(&ev.xkey);
break; break;
@ -360,16 +367,25 @@ main(int argc, char *argv[])
if(ev.xexpose.count == 0) if(ev.xexpose.count == 0)
drawmenu(); drawmenu();
break; break;
default:
break;
} }
} }
XUngrabKeyboard(dpy, CurrentTime); /* cleanup */
while(allitems) {
itm = allitems->next;
free(allitems->text);
free(allitems);
allitems = itm;
}
if(dc.font.set)
XFreeFontSet(dpy, dc.font.set);
else
XFreeFont(dpy, dc.font.xfont);
XFreePixmap(dpy, dc.drawable); XFreePixmap(dpy, dc.drawable);
XFreeGC(dpy, dc.gc); XFreeGC(dpy, dc.gc);
XDestroyWindow(dpy, win); XDestroyWindow(dpy, win);
UninitializedEnd:
XUngrabKeyboard(dpy, CurrentTime);
XCloseDisplay(dpy); XCloseDisplay(dpy);
return ret; return ret;
} }

21
util.c
View File

@ -1,5 +1,4 @@
/* /* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details. * See LICENSE file for license details.
*/ */
#include "dmenu.h" #include "dmenu.h"
@ -13,25 +12,23 @@
/* static */ /* static */
static void static void
bad_malloc(unsigned int size) badmalloc(unsigned int size) {
{
eprint("fatal: could not malloc() %u bytes\n", size); eprint("fatal: could not malloc() %u bytes\n", size);
} }
/* extern */ /* extern */
void * void *
emalloc(unsigned int size) emalloc(unsigned int size) {
{
void *res = malloc(size); void *res = malloc(size);
if(!res) if(!res)
bad_malloc(size); badmalloc(size);
return res; return res;
} }
void void
eprint(const char *errstr, ...) eprint(const char *errstr, ...) {
{
va_list ap; va_list ap;
va_start(ap, errstr); va_start(ap, errstr);
@ -41,10 +38,10 @@ eprint(const char *errstr, ...)
} }
char * char *
estrdup(const char *str) estrdup(const char *str) {
{
void *res = strdup(str); void *res = strdup(str);
if(!res) if(!res)
bad_malloc(strlen(str)); badmalloc(strlen(str));
return res; return res;
} }