diff options
author | Connor Lane Smith <cls@lubutu.com> | 2010-08-02 14:22:54 +0100 |
---|---|---|
committer | Connor Lane Smith <cls@lubutu.com> | 2010-08-02 14:22:54 +0100 |
commit | a7aee433ccfd2590e0785a7b93a89d8d0593a234 (patch) | |
tree | 5a6fcb7a210c164c22194674a7b01c7e8cfe2458 | |
parent | a3606ecb0eeaffa752fdf26565ebaaba29b83239 (diff) |
fixed bugs, no more config.h, updated manpage, new libdraw
-rw-r--r-- | Makefile | 24 | ||||
-rw-r--r-- | README | 11 | ||||
-rw-r--r-- | config.def.h | 8 | ||||
-rw-r--r-- | config.mk | 17 | ||||
-rw-r--r-- | dmenu.1 | 98 | ||||
-rw-r--r-- | dmenu.c | 222 | ||||
-rwxr-xr-x | dmenu_path | 2 |
7 files changed, 162 insertions, 220 deletions
@@ -3,9 +3,6 @@ | |||
3 | 3 | ||
4 | include config.mk | 4 | include config.mk |
5 | 5 | ||
6 | SRC = dmenu.c | ||
7 | OBJ = ${SRC:.c=.o} | ||
8 | |||
9 | all: options dmenu | 6 | all: options dmenu |
10 | 7 | ||
11 | options: | 8 | options: |
@@ -14,34 +11,28 @@ options: | |||
14 | @echo "LDFLAGS = ${LDFLAGS}" | 11 | @echo "LDFLAGS = ${LDFLAGS}" |
15 | @echo "CC = ${CC}" | 12 | @echo "CC = ${CC}" |
16 | 13 | ||
17 | .c.o: | 14 | dmenu.o: dmenu.c config.mk |
18 | @echo CC $< | 15 | @echo CC $< |
19 | @${CC} -c ${CFLAGS} $< | 16 | @${CC} -c ${CFLAGS} $< |
20 | 17 | ||
21 | ${OBJ}: config.h config.mk | 18 | dmenu: dmenu.o |
22 | |||
23 | config.h: | ||
24 | @echo creating $@ from config.def.h | ||
25 | @cp config.def.h $@ | ||
26 | |||
27 | dmenu: ${OBJ} | ||
28 | @echo CC -o $@ | 19 | @echo CC -o $@ |
29 | @${CC} -o $@ $+ ${LDFLAGS} | 20 | @${CC} -o $@ $+ ${LDFLAGS} |
30 | 21 | ||
31 | clean: | 22 | clean: |
32 | @echo cleaning | 23 | @echo cleaning |
33 | @rm -f dmenu ${OBJ} dmenu-${VERSION}.tar.gz | 24 | @rm -f dmenu dmenu.o dmenu-${VERSION}.tar.gz |
34 | 25 | ||
35 | dist: clean | 26 | dist: clean |
36 | @echo creating dist tarball | 27 | @echo creating dist tarball |
37 | @mkdir -p dmenu-${VERSION} | 28 | @mkdir -p dmenu-${VERSION} |
38 | @cp -R LICENSE Makefile README config.mk dmenu.1 config.def.h dmenu_path dmenu_run ${SRC} dmenu-${VERSION} | 29 | @cp -R LICENSE Makefile README config.mk dmenu.1 dmenu.c dmenu_path dmenu_run dmenu-${VERSION} |
39 | @tar -cf dmenu-${VERSION}.tar dmenu-${VERSION} | 30 | @tar -cf dmenu-${VERSION}.tar dmenu-${VERSION} |
40 | @gzip dmenu-${VERSION}.tar | 31 | @gzip dmenu-${VERSION}.tar |
41 | @rm -rf dmenu-${VERSION} | 32 | @rm -rf dmenu-${VERSION} |
42 | 33 | ||
43 | install: all | 34 | install: all |
44 | @echo installing executable file to ${DESTDIR}${PREFIX}/bin | 35 | @echo installing executables to ${DESTDIR}${PREFIX}/bin |
45 | @mkdir -p ${DESTDIR}${PREFIX}/bin | 36 | @mkdir -p ${DESTDIR}${PREFIX}/bin |
46 | @cp -f dmenu dmenu_path dmenu_run ${DESTDIR}${PREFIX}/bin | 37 | @cp -f dmenu dmenu_path dmenu_run ${DESTDIR}${PREFIX}/bin |
47 | @chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu | 38 | @chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu |
@@ -53,8 +44,9 @@ install: all | |||
53 | @chmod 644 ${DESTDIR}${MANPREFIX}/man1/dmenu.1 | 44 | @chmod 644 ${DESTDIR}${MANPREFIX}/man1/dmenu.1 |
54 | 45 | ||
55 | uninstall: | 46 | uninstall: |
56 | @echo removing executable file from ${DESTDIR}${PREFIX}/bin | 47 | @echo removing executables from ${DESTDIR}${PREFIX}/bin |
57 | @rm -f ${DESTDIR}${PREFIX}/bin/dmenu ${DESTDIR}${PREFIX}/bin/dmenu_path | 48 | @rm -f ${DESTDIR}${PREFIX}/bin/dmenu |
49 | @rm -f ${DESTDIR}${PREFIX}/bin/dmenu_path | ||
58 | @rm -f ${DESTDIR}${PREFIX}/bin/dmenu_run | 50 | @rm -f ${DESTDIR}${PREFIX}/bin/dmenu_run |
59 | @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 | 51 | @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 |
60 | @rm -f ${DESTDIR}${MANPREFIX}/man1/dmenu.1 | 52 | @rm -f ${DESTDIR}${MANPREFIX}/man1/dmenu.1 |
@@ -1,21 +1,22 @@ | |||
1 | dmenu - dynamic menu | 1 | dmenu - dynamic menu |
2 | ==================== | 2 | ==================== |
3 | dmenu is a generic and efficient menu for X. | 3 | dmenu is an efficient dynamic menu for X. |
4 | 4 | ||
5 | 5 | ||
6 | Requirements | 6 | Requirements |
7 | ------------ | 7 | ------------ |
8 | In order to build dmenu you need the Xlib header files. | 8 | In order to build dmenu you need the Xlib header files. |
9 | |||
9 | You also need libdraw, available from http://hg.suckless.org/libdraw | 10 | You also need libdraw, available from http://hg.suckless.org/libdraw |
10 | 11 | ||
11 | 12 | ||
12 | Installation | 13 | Installation |
13 | ------------ | 14 | ------------ |
14 | Edit config.mk to match your local setup (dmenu is installed into the | 15 | Edit config.mk to match your local setup (dmenu is installed into |
15 | /usr/local namespace by default). | 16 | the /usr/local namespace by default). |
16 | 17 | ||
17 | Afterwards enter the following command to build and install dmenu (if | 18 | Afterwards enter the following command to build and install dmenu |
18 | necessary as root): | 19 | (if necessary as root): |
19 | 20 | ||
20 | make clean install | 21 | make clean install |
21 | 22 | ||
diff --git a/config.def.h b/config.def.h deleted file mode 100644 index eae3f08..0000000 --- a/config.def.h +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /* See LICENSE file for copyright and license details. */ | ||
2 | |||
3 | /* appearance */ | ||
4 | static const char *font = "-*-terminus-medium-r-normal-*-14-*-*-*-*-*-*-*"; | ||
5 | static const char *normbgcolor = "#cccccc"; | ||
6 | static const char *normfgcolor = "#000000"; | ||
7 | static const char *selbgcolor = "#0066ff"; | ||
8 | static const char *selfgcolor = "#ffffff"; | ||
@@ -1,5 +1,5 @@ | |||
1 | # dmenu version | 1 | # dmenu version |
2 | VERSION = 4.1.1 | 2 | VERSION = 4.2 |
3 | 3 | ||
4 | # Customize below to fit your system | 4 | # Customize below to fit your system |
5 | 5 | ||
@@ -7,25 +7,22 @@ VERSION = 4.1.1 | |||
7 | PREFIX = /usr/local | 7 | PREFIX = /usr/local |
8 | MANPREFIX = ${PREFIX}/share/man | 8 | MANPREFIX = ${PREFIX}/share/man |
9 | 9 | ||
10 | # Xlib | ||
10 | X11INC = /usr/X11R6/include | 11 | X11INC = /usr/X11R6/include |
11 | X11LIB = /usr/X11R6/lib | 12 | X11LIB = /usr/X11R6/lib |
12 | 13 | ||
13 | # Xinerama, comment if you don't want it | 14 | # Xinerama, comment if you don't want it |
14 | XINERAMALIBS = -L${X11LIB} -lXinerama | 15 | XINERAMALIBS = -lXinerama |
15 | XINERAMAFLAGS = -DXINERAMA | 16 | XINERAMAFLAGS = -DXINERAMA |
16 | 17 | ||
17 | # includes and libs | 18 | # includes and libs |
18 | INCS = -I. -I/usr/include -I${X11INC} | 19 | INCS = -I${X11INC} |
19 | LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -ldraw ${XINERAMALIBS} | 20 | LIBS = -L${X11LIB} -ldraw -lX11 ${XINERAMALIBS} |
20 | 21 | ||
21 | # flags | 22 | # flags |
22 | CPPFLAGS = -D_BSD_SOURCE -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} | 23 | CPPFLAGS = -D_BSD_SOURCE -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} |
23 | CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} | 24 | CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} |
24 | LDFLAGS = -s ${LIBS} | 25 | LDFLAGS = -s ${LIBS} |
25 | |||
26 | # Solaris | ||
27 | #CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" | ||
28 | #LDFLAGS = ${LIBS} | ||
29 | 26 | ||
30 | # compiler and linker | 27 | # compiler and linker |
31 | CC = cc | 28 | CC = cc |
@@ -5,81 +5,76 @@ dmenu \- dynamic menu | |||
5 | .B dmenu | 5 | .B dmenu |
6 | .RB [ \-b ] | 6 | .RB [ \-b ] |
7 | .RB [ \-i ] | 7 | .RB [ \-i ] |
8 | .RB [ \-l " <lines>]" | 8 | .RB [ \-l |
9 | .RB [ \-p " <prompt>]" | 9 | .IR lines ] |
10 | .RB [ \-fn " <font>]" | 10 | .RB [ \-p |
11 | .RB [ \-nb " <color>]" | 11 | .IR prompt ] |
12 | .RB [ \-nf " <color>]" | 12 | .RB [ \-fn |
13 | .RB [ \-sb " <color>]" | 13 | .IR font ] |
14 | .RB [ \-sf " <color>]" | 14 | .RB [ \-nb |
15 | .IR color ] | ||
16 | .RB [ \-nf | ||
17 | .IR color ] | ||
18 | .RB [ \-sb | ||
19 | .IR color ] | ||
20 | .RB [ \-sf | ||
21 | .IR color ] | ||
15 | .RB [ \-v ] | 22 | .RB [ \-v ] |
16 | 23 | .P | |
17 | .B dmenu_run | 24 | .BR dmenu_run " ..." |
18 | .RB [ \-b ] | 25 | .P |
19 | .RB [ \-i ] | ||
20 | .RB [ \-l " <lines>]" | ||
21 | .RB [ \-p " <prompt>]" | ||
22 | .RB [ \-fn " <font>]" | ||
23 | .RB [ \-nb " <color>]" | ||
24 | .RB [ \-nf " <color>]" | ||
25 | .RB [ \-sb " <color>]" | ||
26 | .RB [ \-sf " <color>]" | ||
27 | .RB [ \-v ] | ||
28 | |||
29 | .B dmenu_path | 26 | .B dmenu_path |
30 | .SH DESCRIPTION | 27 | .SH DESCRIPTION |
31 | .SS Overview | ||
32 | .B dmenu | 28 | .B dmenu |
33 | is a generic menu for X, originally designed for | 29 | is a dynamic menu for X, originally designed for |
34 | .BR dwm (1). | 30 | .BR dwm (1). |
35 | It manages huge amounts (10000 and more) of user defined menu items efficiently. | 31 | It manages huge numbers of user-defined menu items efficiently. |
32 | .P | ||
33 | dmenu reads a list of newline-separated items from standard input and creates a | ||
34 | menu. When the user selects an item or enters any text and presses Return, | ||
35 | their choice is printed to standard output and dmenu terminates. | ||
36 | .P | 36 | .P |
37 | .B dmenu_run | 37 | .B dmenu_run |
38 | is a dmenu script which lists programs in the user's PATH and executes | 38 | is a dmenu script used by dwm which lists programs in the user's PATH and |
39 | the selected item. | 39 | executes the selected item. |
40 | .P | 40 | .P |
41 | .B dmenu_path | 41 | .B dmenu_path |
42 | is a script used by | 42 | is a script used by dmenu_run to find and cache a list of programs. |
43 | .I dmenu_run | 43 | .SH OPTIONS |
44 | to find and cache a list of programs. | ||
45 | .SS Options | ||
46 | .TP | 44 | .TP |
47 | .B \-b | 45 | .B \-b |
48 | dmenu appears at the bottom of the screen. | 46 | dmenu appears at the bottom of the screen. |
49 | .TP | 47 | .TP |
50 | .B \-i | 48 | .B \-i |
51 | dmenu matches menu entries case insensitively. | 49 | dmenu matches menu items case insensitively. |
52 | .TP | 50 | .TP |
53 | .B \-l <lines> | 51 | .BI \-l " lines" |
54 | dmenu lists items vertically, with the given number of lines. | 52 | dmenu lists items vertically, with the given number of lines. |
55 | .TP | 53 | .TP |
56 | .B \-p <prompt> | 54 | .BI \-p " prompt" |
57 | sets the prompt to be displayed to the left of the input area. | 55 | defines the prompt to be displayed to the left of the input area. |
58 | .TP | 56 | .TP |
59 | .B \-fn <font> | 57 | .BI \-fn " font" |
60 | sets the font. | 58 | defines the font set used. |
61 | .TP | 59 | .TP |
62 | .B \-nb <color> | 60 | .BI \-nb " color" |
63 | sets the background color (#RGB, #RRGGBB, and color names are supported). | 61 | defines the normal background color. |
62 | .IR #RGB , | ||
63 | .IR #RRGGBB , | ||
64 | and color names are supported. | ||
64 | .TP | 65 | .TP |
65 | .B \-nf <color> | 66 | .BI \-nf " color" |
66 | sets the foreground color (#RGB, #RRGGBB, and color names are supported). | 67 | defines the normal foreground color. |
67 | .TP | 68 | .TP |
68 | .B \-sb <color> | 69 | .BI \-sb " color" |
69 | sets the background color of selected items (#RGB, #RRGGBB, and color names are | 70 | defines the selected background color. |
70 | supported). | ||
71 | .TP | 71 | .TP |
72 | .B \-sf <color> | 72 | .BI \-sf " color" |
73 | sets the foreground color of selected items (#RGB, #RRGGBB, and color names are | 73 | defines the selected foreground color. |
74 | supported). | ||
75 | .TP | 74 | .TP |
76 | .B \-v | 75 | .B \-v |
77 | prints version information to standard output, then exits. | 76 | prints version information to standard output, then exits. |
78 | .SH USAGE | 77 | .SH USAGE |
79 | dmenu reads a list of newline-separated items from standard input and creates a | ||
80 | menu. When the user selects an item or enters any text and presses Return, | ||
81 | their choice is printed to standard output and dmenu terminates. | ||
82 | .P | ||
83 | dmenu is completely controlled by the keyboard. Besides standard Unix line | 78 | dmenu is completely controlled by the keyboard. Besides standard Unix line |
84 | editing and item selection (Up/Down/Left/Right, PageUp/PageDown, Home/End), the | 79 | editing and item selection (Up/Down/Left/Right, PageUp/PageDown, Home/End), the |
85 | following keys are recognized: | 80 | following keys are recognized: |
@@ -96,10 +91,9 @@ Confirm input. Prints the input text to standard output and exits, returning | |||
96 | success. | 91 | success. |
97 | .TP | 92 | .TP |
98 | .B Escape (Control\-c) | 93 | .B Escape (Control\-c) |
99 | Quit without selecting an item, returning failure. | 94 | Exit without selecting an item, returning failure. |
100 | .TP | 95 | .TP |
101 | .B Control\-y | 96 | .B Control\-y |
102 | Paste the current X selection into the input field. | 97 | Paste the current X selection into the input field. |
103 | .SH SEE ALSO | 98 | .SH SEE ALSO |
104 | .BR dwm (1), | 99 | .BR dwm (1) |
105 | .BR wmii (1). | ||
@@ -1,11 +1,9 @@ | |||
1 | /* See LICENSE file for copyright and license details. */ | 1 | /* See LICENSE file for copyright and license details. */ |
2 | #include <ctype.h> | 2 | #include <ctype.h> |
3 | #include <locale.h> | ||
4 | #include <stdio.h> | 3 | #include <stdio.h> |
5 | #include <stdlib.h> | 4 | #include <stdlib.h> |
6 | #include <string.h> | 5 | #include <string.h> |
7 | #include <unistd.h> | 6 | #include <unistd.h> |
8 | #include <X11/keysym.h> | ||
9 | #include <X11/Xatom.h> | 7 | #include <X11/Xatom.h> |
10 | #include <X11/Xlib.h> | 8 | #include <X11/Xlib.h> |
11 | #include <X11/Xutil.h> | 9 | #include <X11/Xutil.h> |
@@ -13,7 +11,6 @@ | |||
13 | #include <X11/extensions/Xinerama.h> | 11 | #include <X11/extensions/Xinerama.h> |
14 | #endif | 12 | #endif |
15 | #include <draw.h> | 13 | #include <draw.h> |
16 | #include "config.h" | ||
17 | 14 | ||
18 | #define INRECT(x,y,rx,ry,rw,rh) ((x) >= (rx) && (x) < (rx)+(rw) && (y) >= (ry) && (y) < (ry)+(rh)) | 15 | #define INRECT(x,y,rx,ry,rw,rh) ((x) >= (rx) && (x) < (rx)+(rw) && (y) >= (ry) && (y) < (ry)+(rh)) |
19 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) | 16 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) |
@@ -38,25 +35,27 @@ static void grabkeyboard(void); | |||
38 | static void insert(const char *s, ssize_t n); | 35 | static void insert(const char *s, ssize_t n); |
39 | static void keypress(XKeyEvent *e); | 36 | static void keypress(XKeyEvent *e); |
40 | static void match(void); | 37 | static void match(void); |
41 | static void paste(Atom atom); | 38 | static void paste(void); |
42 | static void readstdin(void); | 39 | static void readstdin(void); |
43 | static void run(void); | 40 | static void run(void); |
44 | static void setup(void); | 41 | static void setup(void); |
45 | static void usage(void); | 42 | static void usage(void); |
46 | 43 | ||
47 | static char *prompt; | ||
48 | static char text[4096]; | 44 | static char text[4096]; |
49 | static int screen; | ||
50 | static size_t cursor = 0; | 45 | static size_t cursor = 0; |
46 | static const char *prompt = NULL; | ||
47 | static const char *normbgcolor = "#cccccc"; | ||
48 | static const char *normfgcolor = "#000000"; | ||
49 | static const char *selbgcolor = "#0066ff"; | ||
50 | static const char *selfgcolor = "#ffffff"; | ||
51 | static unsigned int inputw = 0; | 51 | static unsigned int inputw = 0; |
52 | static unsigned int lines = 0; | 52 | static unsigned int lines = 0; |
53 | static unsigned int mw, mh; | 53 | static unsigned int mw, mh; |
54 | static unsigned int promptw = 0; | ||
55 | static unsigned long normcol[ColLast]; | 54 | static unsigned long normcol[ColLast]; |
56 | static unsigned long selcol[ColLast]; | 55 | static unsigned long selcol[ColLast]; |
57 | static Atom utf8; | 56 | static Atom utf8; |
58 | static Bool topbar = True; | 57 | static Bool topbar = True; |
59 | static DC dc; | 58 | static DC *dc; |
60 | static Item *allitems, *matches; | 59 | static Item *allitems, *matches; |
61 | static Item *curr, *prev, *next, *sel; | 60 | static Item *curr, *prev, *next, *sel; |
62 | static Window root, win; | 61 | static Window root, win; |
@@ -67,7 +66,7 @@ static void (*calcoffsets)(void) = calcoffsetsh; | |||
67 | 66 | ||
68 | void | 67 | void |
69 | appenditem(Item *item, Item **list, Item **last) { | 68 | appenditem(Item *item, Item **list, Item **last) { |
70 | if(!(*last)) | 69 | if(!*last) |
71 | *list = item; | 70 | *list = item; |
72 | else | 71 | else |
73 | (*last)->right = item; | 72 | (*last)->right = item; |
@@ -80,12 +79,12 @@ void | |||
80 | calcoffsetsh(void) { | 79 | calcoffsetsh(void) { |
81 | unsigned int w, x; | 80 | unsigned int w, x; |
82 | 81 | ||
83 | w = promptw + inputw + textw(&dc, "<") + textw(&dc, ">"); | 82 | w = (prompt ? textw(dc, prompt) : 0) + inputw + textw(dc, "<") + textw(dc, ">"); |
84 | for(x = w, next = curr; next; next = next->right) | 83 | for(x = w, next = curr; next; next = next->right) |
85 | if((x += MIN(textw(&dc, next->text), mw / 3)) > mw) | 84 | if((x += MIN(textw(dc, next->text), mw / 3)) > mw) |
86 | break; | 85 | break; |
87 | for(x = w, prev = curr; prev && prev->left; prev = prev->left) | 86 | for(x = w, prev = curr; prev && prev->left; prev = prev->left) |
88 | if((x += MIN(textw(&dc, prev->left->text), mw / 3)) > mw) | 87 | if((x += MIN(textw(dc, prev->left->text), mw / 3)) > mw) |
89 | break; | 88 | break; |
90 | } | 89 | } |
91 | 90 | ||
@@ -96,101 +95,75 @@ calcoffsetsv(void) { | |||
96 | next = prev = curr; | 95 | next = prev = curr; |
97 | for(i = 0; i < lines && next; i++) | 96 | for(i = 0; i < lines && next; i++) |
98 | next = next->right; | 97 | next = next->right; |
99 | mh = (dc.font.height + 2) * (i + 1); | ||
100 | for(i = 0; i < lines && prev && prev->left; i++) | 98 | for(i = 0; i < lines && prev && prev->left; i++) |
101 | prev = prev->left; | 99 | prev = prev->left; |
102 | } | 100 | } |
103 | 101 | ||
104 | char * | 102 | char * |
105 | cistrstr(const char *s, const char *sub) { | 103 | cistrstr(const char *s, const char *sub) { |
106 | int c, csub; | 104 | size_t len; |
107 | unsigned int len; | ||
108 | 105 | ||
109 | if(!sub) | 106 | for(len = strlen(sub); *s; s++) |
110 | return (char *)s; | 107 | if(!strncasecmp(s, sub, len)) |
111 | if((c = tolower(*sub++)) != '\0') { | 108 | return (char *)s; |
112 | len = strlen(sub); | 109 | return NULL; |
113 | do { | ||
114 | do { | ||
115 | if((csub = *s++) == '\0') | ||
116 | return NULL; | ||
117 | } | ||
118 | while(tolower(csub) != c); | ||
119 | } | ||
120 | while(strncasecmp(s, sub, len) != 0); | ||
121 | s--; | ||
122 | } | ||
123 | return (char *)s; | ||
124 | } | 110 | } |
125 | 111 | ||
126 | void | 112 | void |
127 | drawmenu(void) { | 113 | drawmenu(void) { |
128 | dc.x = 0; | 114 | dc->x = 0; |
129 | dc.y = 0; | 115 | dc->y = 0; |
130 | dc.w = mw; | 116 | drawrect(dc, 0, 0, mw, mh, BG(dc, normcol)); |
131 | dc.h = mh; | 117 | dc->h = dc->font.height + 2; |
132 | drawbox(&dc, normcol); | 118 | dc->y = topbar ? 0 : mh - dc->h; |
133 | dc.h = dc.font.height + 2; | ||
134 | dc.y = topbar ? 0 : mh - dc.h; | ||
135 | /* print prompt? */ | 119 | /* print prompt? */ |
136 | if(prompt) { | 120 | if(prompt) { |
137 | dc.w = promptw; | 121 | dc->w = textw(dc, prompt); |
138 | drawbox(&dc, selcol); | 122 | drawtext(dc, prompt, selcol); |
139 | drawtext(&dc, prompt, selcol); | 123 | dc->x = dc->w; |
140 | dc.x += dc.w; | ||
141 | } | 124 | } |
142 | dc.w = mw - dc.x; | 125 | dc->w = mw - dc->x; |
143 | /* print input area */ | 126 | /* print input area */ |
144 | if(matches && lines == 0 && textw(&dc, text) <= inputw) | 127 | if(matches && lines == 0 && textw(dc, text) <= inputw) |
145 | dc.w = inputw; | 128 | dc->w = inputw; |
146 | drawtext(&dc, text, normcol); | 129 | drawtext(dc, text, normcol); |
147 | drawline(&dc, textnw(&dc, text, cursor) + dc.h/2 - 2, 2, 1, dc.h-4, normcol); | 130 | drawrect(dc, textnw(dc, text, cursor) + dc->h/2 - 2, 2, 1, dc->h - 4, FG(dc, normcol)); |
148 | if(lines > 0) | 131 | if(lines > 0) |
149 | drawmenuv(); | 132 | drawmenuv(); |
150 | else if(curr && (dc.w == inputw || curr->next)) | 133 | else if(curr && (dc->w == inputw || curr->next)) |
151 | drawmenuh(); | 134 | drawmenuh(); |
152 | commitdraw(&dc, win); | 135 | commitdraw(dc, win); |
153 | } | 136 | } |
154 | 137 | ||
155 | void | 138 | void |
156 | drawmenuh(void) { | 139 | drawmenuh(void) { |
157 | Item *item; | 140 | Item *item; |
158 | 141 | ||
159 | dc.x += inputw; | 142 | dc->x += inputw; |
160 | dc.w = textw(&dc, "<"); | 143 | dc->w = textw(dc, "<"); |
161 | if(curr->left) | 144 | if(curr->left) |
162 | drawtext(&dc, "<", normcol); | 145 | drawtext(dc, "<", normcol); |
163 | dc.x += dc.w; | ||
164 | for(item = curr; item != next; item = item->right) { | 146 | for(item = curr; item != next; item = item->right) { |
165 | dc.w = MIN(textw(&dc, item->text), mw / 3); | 147 | dc->x += dc->w; |
166 | if(item == sel) | 148 | dc->w = MIN(textw(dc, item->text), mw / 3); |
167 | drawbox(&dc, selcol); | 149 | drawtext(dc, item->text, (item == sel) ? selcol : normcol); |
168 | drawtext(&dc, item->text, (item == sel) ? selcol : normcol); | ||
169 | dc.x += dc.w; | ||
170 | } | 150 | } |
171 | dc.w = textw(&dc, ">"); | 151 | dc->w = textw(dc, ">"); |
172 | dc.x = mw - dc.w; | 152 | dc->x = mw - dc->w; |
173 | if(next) | 153 | if(next) |
174 | drawtext(&dc, ">", normcol); | 154 | drawtext(dc, ">", normcol); |
175 | } | 155 | } |
176 | 156 | ||
177 | void | 157 | void |
178 | drawmenuv(void) { | 158 | drawmenuv(void) { |
179 | Item *item; | 159 | Item *item; |
180 | XWindowAttributes wa; | ||
181 | 160 | ||
182 | dc.y = topbar ? dc.h : 0; | 161 | dc->y = topbar ? dc->h : 0; |
183 | dc.w = mw - dc.x; | 162 | dc->w = mw - dc->x; |
184 | for(item = curr; item != next; item = item->right) { | 163 | for(item = curr; item != next; item = item->right) { |
185 | if(item == sel) | 164 | drawtext(dc, item->text, (item == sel) ? selcol : normcol); |
186 | drawbox(&dc, selcol); | 165 | dc->y += dc->h; |
187 | drawtext(&dc, item->text, (item == sel) ? selcol : normcol); | ||
188 | dc.y += dc.h; | ||
189 | } | 166 | } |
190 | if(!XGetWindowAttributes(dc.dpy, win, &wa)) | ||
191 | eprintf("cannot get window attributes\n"); | ||
192 | if(wa.height != mh) | ||
193 | XMoveResizeWindow(dc.dpy, win, wa.x, wa.y + (topbar ? 0 : wa.height - mh), mw, mh); | ||
194 | } | 167 | } |
195 | 168 | ||
196 | void | 169 | void |
@@ -198,7 +171,7 @@ grabkeyboard(void) { | |||
198 | int i; | 171 | int i; |
199 | 172 | ||
200 | for(i = 0; i < 1000; i++) { | 173 | for(i = 0; i < 1000; i++) { |
201 | if(!XGrabKeyboard(dc.dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime)) | 174 | if(!XGrabKeyboard(dc->dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime)) |
202 | return; | 175 | return; |
203 | usleep(1000); | 176 | usleep(1000); |
204 | } | 177 | } |
@@ -254,6 +227,7 @@ keypress(XKeyEvent *e) { | |||
254 | break; | 227 | break; |
255 | case XK_k: /* delete right */ | 228 | case XK_k: /* delete right */ |
256 | text[cursor] = '\0'; | 229 | text[cursor] = '\0'; |
230 | match(); | ||
257 | break; | 231 | break; |
258 | case XK_n: | 232 | case XK_n: |
259 | ksym = XK_Down; | 233 | ksym = XK_Down; |
@@ -270,10 +244,10 @@ keypress(XKeyEvent *e) { | |||
270 | n = 0; | 244 | n = 0; |
271 | while(cursor - n++ > 0 && text[cursor - n] == ' '); | 245 | while(cursor - n++ > 0 && text[cursor - n] == ' '); |
272 | while(cursor - n++ > 0 && text[cursor - n] != ' '); | 246 | while(cursor - n++ > 0 && text[cursor - n] != ' '); |
273 | insert(NULL, -(--n)); | 247 | insert(NULL, 1-n); |
274 | break; | 248 | break; |
275 | case XK_y: /* paste selection */ | 249 | case XK_y: /* paste selection */ |
276 | XConvertSelection(dc.dpy, XA_PRIMARY, utf8, None, win, CurrentTime); | 250 | XConvertSelection(dc->dpy, XA_PRIMARY, utf8, None, win, CurrentTime); |
277 | /* causes SelectionNotify event */ | 251 | /* causes SelectionNotify event */ |
278 | return; | 252 | return; |
279 | } | 253 | } |
@@ -348,7 +322,7 @@ keypress(XKeyEvent *e) { | |||
348 | break; | 322 | break; |
349 | case XK_Return: | 323 | case XK_Return: |
350 | case XK_KP_Enter: | 324 | case XK_KP_Enter: |
351 | fputs(((e->state & ShiftMask) || sel) ? sel->text : text, stdout); | 325 | fputs((sel && !(e->state & ShiftMask)) ? sel->text : text, stdout); |
352 | fflush(stdout); | 326 | fflush(stdout); |
353 | exit(EXIT_SUCCESS); | 327 | exit(EXIT_SUCCESS); |
354 | case XK_Right: | 328 | case XK_Right: |
@@ -418,15 +392,14 @@ match(void) { | |||
418 | } | 392 | } |
419 | 393 | ||
420 | void | 394 | void |
421 | paste(Atom atom) | 395 | paste(void) { |
422 | { | ||
423 | char *p, *q; | 396 | char *p, *q; |
424 | int di; | 397 | int di; |
425 | unsigned long dl; | 398 | unsigned long dl; |
426 | Atom da; | 399 | Atom da; |
427 | 400 | ||
428 | XGetWindowProperty(dc.dpy, win, atom, 0, sizeof text - cursor, True, | 401 | XGetWindowProperty(dc->dpy, win, utf8, 0, sizeof text - cursor, True, |
429 | utf8, &da, &di, &dl, &dl, (unsigned char **)&p); | 402 | utf8, &da, &di, &dl, &dl, (unsigned char **)&p); |
430 | insert(p, (q = strchr(p, '\n')) ? q-p : strlen(p)); | 403 | insert(p, (q = strchr(p, '\n')) ? q-p : strlen(p)); |
431 | XFree(p); | 404 | XFree(p); |
432 | drawmenu(); | 405 | drawmenu(); |
@@ -434,24 +407,22 @@ paste(Atom atom) | |||
434 | 407 | ||
435 | void | 408 | void |
436 | readstdin(void) { | 409 | readstdin(void) { |
437 | char buf[sizeof text]; | 410 | char buf[sizeof text], *p; |
438 | size_t len; | ||
439 | Item *item, *new; | 411 | Item *item, *new; |
440 | 412 | ||
441 | allitems = NULL; | 413 | allitems = NULL; |
442 | for(item = NULL; fgets(buf, sizeof buf, stdin); item = new) { | 414 | for(item = NULL; fgets(buf, sizeof buf, stdin); item = new) { |
443 | len = strlen(buf); | 415 | if((p = strchr(buf, '\n'))) |
444 | if(buf[len-1] == '\n') | 416 | *p = '\0'; |
445 | buf[--len] = '\0'; | ||
446 | if(!(new = malloc(sizeof *new))) | 417 | if(!(new = malloc(sizeof *new))) |
447 | eprintf("cannot malloc %u bytes\n", sizeof *new); | 418 | eprintf("cannot malloc %u bytes\n", sizeof *new); |
448 | if(!(new->text = strdup(buf))) | 419 | if(!(new->text = strdup(buf))) |
449 | eprintf("cannot strdup %u bytes\n", len); | 420 | eprintf("cannot strdup %u bytes\n", strlen(buf)); |
450 | inputw = MAX(inputw, textw(&dc, new->text)); | 421 | inputw = MAX(inputw, textw(dc, new->text)); |
451 | new->next = new->left = new->right = NULL; | 422 | new->next = new->left = new->right = NULL; |
452 | if(item) | 423 | if(item) |
453 | item->next = new; | 424 | item->next = new; |
454 | else | 425 | else |
455 | allitems = new; | 426 | allitems = new; |
456 | } | 427 | } |
457 | } | 428 | } |
@@ -460,7 +431,7 @@ void | |||
460 | run(void) { | 431 | run(void) { |
461 | XEvent ev; | 432 | XEvent ev; |
462 | 433 | ||
463 | while(!XNextEvent(dc.dpy, &ev)) | 434 | while(!XNextEvent(dc->dpy, &ev)) |
464 | switch(ev.type) { | 435 | switch(ev.type) { |
465 | case Expose: | 436 | case Expose: |
466 | if(ev.xexpose.count == 0) | 437 | if(ev.xexpose.count == 0) |
@@ -470,39 +441,43 @@ run(void) { | |||
470 | keypress(&ev.xkey); | 441 | keypress(&ev.xkey); |
471 | break; | 442 | break; |
472 | case SelectionNotify: | 443 | case SelectionNotify: |
473 | if(ev.xselection.property != None) | 444 | if(ev.xselection.property == utf8) |
474 | paste(ev.xselection.property); | 445 | paste(); |
475 | break; | 446 | break; |
476 | case VisibilityNotify: | 447 | case VisibilityNotify: |
477 | if(ev.xvisibility.state != VisibilityUnobscured) | 448 | if(ev.xvisibility.state != VisibilityUnobscured) |
478 | XRaiseWindow(dc.dpy, win); | 449 | XRaiseWindow(dc->dpy, win); |
479 | break; | 450 | break; |
480 | } | 451 | } |
481 | } | 452 | } |
482 | 453 | ||
483 | void | 454 | void |
484 | setup(void) { | 455 | setup(void) { |
485 | int x, y; | 456 | int x, y, screen; |
457 | XSetWindowAttributes wa; | ||
486 | #ifdef XINERAMA | 458 | #ifdef XINERAMA |
487 | int i, n; | 459 | int n; |
488 | XineramaScreenInfo *info; | 460 | XineramaScreenInfo *info; |
489 | #endif | 461 | #endif |
490 | XSetWindowAttributes wa; | ||
491 | 462 | ||
492 | normcol[ColBG] = getcolor(&dc, normbgcolor); | 463 | screen = DefaultScreen(dc->dpy); |
493 | normcol[ColFG] = getcolor(&dc, normfgcolor); | 464 | root = RootWindow(dc->dpy, screen); |
494 | selcol[ColBG] = getcolor(&dc, selbgcolor); | 465 | utf8 = XInternAtom(dc->dpy, "UTF8_STRING", False); |
495 | selcol[ColFG] = getcolor(&dc, selfgcolor); | 466 | |
467 | normcol[ColBG] = getcolor(dc, normbgcolor); | ||
468 | normcol[ColFG] = getcolor(dc, normfgcolor); | ||
469 | selcol[ColBG] = getcolor(dc, selbgcolor); | ||
470 | selcol[ColFG] = getcolor(dc, selfgcolor); | ||
496 | 471 | ||
497 | /* input window geometry */ | 472 | /* input window geometry */ |
498 | mh = (dc.font.height + 2) * (lines + 1); | 473 | mh = (dc->font.height + 2) * (lines + 1); |
499 | #ifdef XINERAMA | 474 | #ifdef XINERAMA |
500 | if((info = XineramaQueryScreens(dc.dpy, &n))) { | 475 | if((info = XineramaQueryScreens(dc->dpy, &n))) { |
501 | int di; | 476 | int i, di; |
502 | unsigned int du; | 477 | unsigned int du; |
503 | Window dw; | 478 | Window dw; |
504 | 479 | ||
505 | XQueryPointer(dc.dpy, root, &dw, &dw, &x, &y, &di, &di, &du); | 480 | XQueryPointer(dc->dpy, root, &dw, &dw, &x, &y, &di, &di, &du); |
506 | for(i = 0; i < n; i++) | 481 | for(i = 0; i < n; i++) |
507 | if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height)) | 482 | if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height)) |
508 | break; | 483 | break; |
@@ -515,31 +490,30 @@ setup(void) { | |||
515 | #endif | 490 | #endif |
516 | { | 491 | { |
517 | x = 0; | 492 | x = 0; |
518 | y = topbar ? 0 : DisplayHeight(dc.dpy, screen) - mh; | 493 | y = topbar ? 0 : DisplayHeight(dc->dpy, screen) - mh; |
519 | mw = DisplayWidth(dc.dpy, screen); | 494 | mw = DisplayWidth(dc->dpy, screen); |
520 | } | 495 | } |
521 | 496 | ||
522 | /* input window */ | 497 | /* input window */ |
523 | wa.override_redirect = True; | 498 | wa.override_redirect = True; |
524 | wa.background_pixmap = ParentRelative; | 499 | wa.background_pixmap = ParentRelative; |
525 | wa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; | 500 | wa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; |
526 | win = XCreateWindow(dc.dpy, root, x, y, mw, mh, 0, | 501 | win = XCreateWindow(dc->dpy, root, x, y, mw, mh, 0, |
527 | DefaultDepth(dc.dpy, screen), CopyFromParent, | 502 | DefaultDepth(dc->dpy, screen), CopyFromParent, |
528 | DefaultVisual(dc.dpy, screen), | 503 | DefaultVisual(dc->dpy, screen), |
529 | CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); | 504 | CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); |
530 | 505 | ||
531 | match(); | ||
532 | grabkeyboard(); | 506 | grabkeyboard(); |
533 | setupdraw(&dc, win); | 507 | setcanvas(dc, win, mw, mh); |
534 | inputw = MIN(inputw, mw / 3); | 508 | inputw = MIN(inputw, mw/3); |
535 | utf8 = XInternAtom(dc.dpy, "UTF8_STRING", False); | 509 | XMapRaised(dc->dpy, win); |
536 | XMapRaised(dc.dpy, win); | 510 | match(); |
537 | } | 511 | } |
538 | 512 | ||
539 | void | 513 | void |
540 | usage(void) { | 514 | usage(void) { |
541 | fputs("usage: dmenu [-b] [-i] [-l <lines>] [-p <prompt>] [-fn <font>] [-nb <color>]\n" | 515 | fputs("usage: dmenu [-b] [-i] [-l lines] [-p prompt] [-fn font] [-nb color]\n" |
542 | " [-nf <color>] [-sb <color>] [-sf <color>] [-v]\n", stderr); | 516 | " [-nf color] [-sb color] [-sf color] [-v]\n", stderr); |
543 | exit(EXIT_FAILURE); | 517 | exit(EXIT_FAILURE); |
544 | } | 518 | } |
545 | 519 | ||
@@ -548,8 +522,10 @@ main(int argc, char *argv[]) { | |||
548 | int i; | 522 | int i; |
549 | 523 | ||
550 | progname = "dmenu"; | 524 | progname = "dmenu"; |
525 | dc = initdraw(); | ||
526 | |||
551 | for(i = 1; i < argc; i++) | 527 | for(i = 1; i < argc; i++) |
552 | /* 1-arg flags */ | 528 | /* single flags */ |
553 | if(!strcmp(argv[i], "-v")) { | 529 | if(!strcmp(argv[i], "-v")) { |
554 | fputs("dmenu-"VERSION", © 2006-2010 dmenu engineers, see LICENSE for details\n", stdout); | 530 | fputs("dmenu-"VERSION", © 2006-2010 dmenu engineers, see LICENSE for details\n", stdout); |
555 | exit(EXIT_SUCCESS); | 531 | exit(EXIT_SUCCESS); |
@@ -562,17 +538,15 @@ main(int argc, char *argv[]) { | |||
562 | } | 538 | } |
563 | else if(i == argc-1) | 539 | else if(i == argc-1) |
564 | usage(); | 540 | usage(); |
565 | /* 2-arg flags */ | 541 | /* double flags */ |
566 | else if(!strcmp(argv[i], "-l")) { | 542 | else if(!strcmp(argv[i], "-l")) { |
567 | if((lines = atoi(argv[++i])) > 0) | 543 | if((lines = atoi(argv[++i])) > 0) |
568 | calcoffsets = calcoffsetsv; | 544 | calcoffsets = calcoffsetsv; |
569 | } | 545 | } |
570 | else if(!strcmp(argv[i], "-p")) { | 546 | else if(!strcmp(argv[i], "-p")) |
571 | prompt = argv[++i]; | 547 | prompt = argv[++i]; |
572 | promptw = MIN(textw(&dc, prompt), mw/5); | ||
573 | } | ||
574 | else if(!strcmp(argv[i], "-fn")) | 548 | else if(!strcmp(argv[i], "-fn")) |
575 | font = argv[++i]; | 549 | initfont(dc, argv[i++]); |
576 | else if(!strcmp(argv[i], "-nb")) | 550 | else if(!strcmp(argv[i], "-nb")) |
577 | normbgcolor = argv[++i]; | 551 | normbgcolor = argv[++i]; |
578 | else if(!strcmp(argv[i], "-nf")) | 552 | else if(!strcmp(argv[i], "-nf")) |
@@ -584,14 +558,6 @@ main(int argc, char *argv[]) { | |||
584 | else | 558 | else |
585 | usage(); | 559 | usage(); |
586 | 560 | ||
587 | if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) | ||
588 | fputs("dmenu: warning: no locale support\n", stderr); | ||
589 | if(!(dc.dpy = XOpenDisplay(NULL))) | ||
590 | eprintf("cannot open display\n"); | ||
591 | screen = DefaultScreen(dc.dpy); | ||
592 | root = RootWindow(dc.dpy, screen); | ||
593 | initfont(&dc, font); | ||
594 | |||
595 | readstdin(); | 561 | readstdin(); |
596 | setup(); | 562 | setup(); |
597 | run(); | 563 | run(); |
@@ -19,7 +19,7 @@ then | |||
19 | do | 19 | do |
20 | test -x "$file" && echo "$file" | 20 | test -x "$file" && echo "$file" |
21 | done | 21 | done |
22 | done | sort | uniq > "$CACHE".$$ && | 22 | done | sort -u > "$CACHE".$$ && |
23 | mv "$CACHE".$$ "$CACHE" | 23 | mv "$CACHE".$$ "$CACHE" |
24 | fi | 24 | fi |
25 | 25 | ||