aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile24
-rw-r--r--README11
-rw-r--r--config.def.h8
-rw-r--r--config.mk17
-rw-r--r--dmenu.198
-rw-r--r--dmenu.c222
-rwxr-xr-xdmenu_path2
7 files changed, 162 insertions, 220 deletions
diff --git a/Makefile b/Makefile
index 269bc27..7b21a25 100644
--- a/Makefile
+++ b/Makefile
@@ -3,9 +3,6 @@
3 3
4include config.mk 4include config.mk
5 5
6SRC = dmenu.c
7OBJ = ${SRC:.c=.o}
8
9all: options dmenu 6all: options dmenu
10 7
11options: 8options:
@@ -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: 14dmenu.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 18dmenu: dmenu.o
22
23config.h:
24 @echo creating $@ from config.def.h
25 @cp config.def.h $@
26
27dmenu: ${OBJ}
28 @echo CC -o $@ 19 @echo CC -o $@
29 @${CC} -o $@ $+ ${LDFLAGS} 20 @${CC} -o $@ $+ ${LDFLAGS}
30 21
31clean: 22clean:
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
35dist: clean 26dist: 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
43install: all 34install: 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
55uninstall: 46uninstall:
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
diff --git a/README b/README
index 9f0583a..98647bf 100644
--- a/README
+++ b/README
@@ -1,21 +1,22 @@
1dmenu - dynamic menu 1dmenu - dynamic menu
2==================== 2====================
3dmenu is a generic and efficient menu for X. 3dmenu is an efficient dynamic menu for X.
4 4
5 5
6Requirements 6Requirements
7------------ 7------------
8In order to build dmenu you need the Xlib header files. 8In order to build dmenu you need the Xlib header files.
9
9You also need libdraw, available from http://hg.suckless.org/libdraw 10You also need libdraw, available from http://hg.suckless.org/libdraw
10 11
11 12
12Installation 13Installation
13------------ 14------------
14Edit config.mk to match your local setup (dmenu is installed into the 15Edit config.mk to match your local setup (dmenu is installed into
15/usr/local namespace by default). 16the /usr/local namespace by default).
16 17
17Afterwards enter the following command to build and install dmenu (if 18Afterwards enter the following command to build and install dmenu
18necessary 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 */
4static const char *font = "-*-terminus-medium-r-normal-*-14-*-*-*-*-*-*-*";
5static const char *normbgcolor = "#cccccc";
6static const char *normfgcolor = "#000000";
7static const char *selbgcolor = "#0066ff";
8static const char *selfgcolor = "#ffffff";
diff --git a/config.mk b/config.mk
index c8bbdcd..d9f5a27 100644
--- a/config.mk
+++ b/config.mk
@@ -1,5 +1,5 @@
1# dmenu version 1# dmenu version
2VERSION = 4.1.1 2VERSION = 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
7PREFIX = /usr/local 7PREFIX = /usr/local
8MANPREFIX = ${PREFIX}/share/man 8MANPREFIX = ${PREFIX}/share/man
9 9
10# Xlib
10X11INC = /usr/X11R6/include 11X11INC = /usr/X11R6/include
11X11LIB = /usr/X11R6/lib 12X11LIB = /usr/X11R6/lib
12 13
13# Xinerama, comment if you don't want it 14# Xinerama, comment if you don't want it
14XINERAMALIBS = -L${X11LIB} -lXinerama 15XINERAMALIBS = -lXinerama
15XINERAMAFLAGS = -DXINERAMA 16XINERAMAFLAGS = -DXINERAMA
16 17
17# includes and libs 18# includes and libs
18INCS = -I. -I/usr/include -I${X11INC} 19INCS = -I${X11INC}
19LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -ldraw ${XINERAMALIBS} 20LIBS = -L${X11LIB} -ldraw -lX11 ${XINERAMALIBS}
20 21
21# flags 22# flags
22CPPFLAGS = -D_BSD_SOURCE -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} 23CPPFLAGS = -D_BSD_SOURCE -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
23CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} 24CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
24LDFLAGS = -s ${LIBS} 25LDFLAGS = -s ${LIBS}
25
26# Solaris
27#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\"
28#LDFLAGS = ${LIBS}
29 26
30# compiler and linker 27# compiler and linker
31CC = cc 28CC = cc
diff --git a/dmenu.1 b/dmenu.1
index 2d8bc20..e1f8393 100644
--- a/dmenu.1
+++ b/dmenu.1
@@ -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
33is a generic menu for X, originally designed for 29is a dynamic menu for X, originally designed for
34.BR dwm (1). 30.BR dwm (1).
35It manages huge amounts (10000 and more) of user defined menu items efficiently. 31It manages huge numbers of user-defined menu items efficiently.
32.P
33dmenu reads a list of newline-separated items from standard input and creates a
34menu. When the user selects an item or enters any text and presses Return,
35their choice is printed to standard output and dmenu terminates.
36.P 36.P
37.B dmenu_run 37.B dmenu_run
38is a dmenu script which lists programs in the user's PATH and executes 38is a dmenu script used by dwm which lists programs in the user's PATH and
39the selected item. 39executes the selected item.
40.P 40.P
41.B dmenu_path 41.B dmenu_path
42is a script used by 42is a script used by dmenu_run to find and cache a list of programs.
43.I dmenu_run 43.SH OPTIONS
44to find and cache a list of programs.
45.SS Options
46.TP 44.TP
47.B \-b 45.B \-b
48dmenu appears at the bottom of the screen. 46dmenu appears at the bottom of the screen.
49.TP 47.TP
50.B \-i 48.B \-i
51dmenu matches menu entries case insensitively. 49dmenu matches menu items case insensitively.
52.TP 50.TP
53.B \-l <lines> 51.BI \-l " lines"
54dmenu lists items vertically, with the given number of lines. 52dmenu lists items vertically, with the given number of lines.
55.TP 53.TP
56.B \-p <prompt> 54.BI \-p " prompt"
57sets the prompt to be displayed to the left of the input area. 55defines the prompt to be displayed to the left of the input area.
58.TP 56.TP
59.B \-fn <font> 57.BI \-fn " font"
60sets the font. 58defines the font set used.
61.TP 59.TP
62.B \-nb <color> 60.BI \-nb " color"
63sets the background color (#RGB, #RRGGBB, and color names are supported). 61defines the normal background color.
62.IR #RGB ,
63.IR #RRGGBB ,
64and color names are supported.
64.TP 65.TP
65.B \-nf <color> 66.BI \-nf " color"
66sets the foreground color (#RGB, #RRGGBB, and color names are supported). 67defines the normal foreground color.
67.TP 68.TP
68.B \-sb <color> 69.BI \-sb " color"
69sets the background color of selected items (#RGB, #RRGGBB, and color names are 70defines the selected background color.
70supported).
71.TP 71.TP
72.B \-sf <color> 72.BI \-sf " color"
73sets the foreground color of selected items (#RGB, #RRGGBB, and color names are 73defines the selected foreground color.
74supported).
75.TP 74.TP
76.B \-v 75.B \-v
77prints version information to standard output, then exits. 76prints version information to standard output, then exits.
78.SH USAGE 77.SH USAGE
79dmenu reads a list of newline-separated items from standard input and creates a
80menu. When the user selects an item or enters any text and presses Return,
81their choice is printed to standard output and dmenu terminates.
82.P
83dmenu is completely controlled by the keyboard. Besides standard Unix line 78dmenu is completely controlled by the keyboard. Besides standard Unix line
84editing and item selection (Up/Down/Left/Right, PageUp/PageDown, Home/End), the 79editing and item selection (Up/Down/Left/Right, PageUp/PageDown, Home/End), the
85following keys are recognized: 80following keys are recognized:
@@ -96,10 +91,9 @@ Confirm input. Prints the input text to standard output and exits, returning
96success. 91success.
97.TP 92.TP
98.B Escape (Control\-c) 93.B Escape (Control\-c)
99Quit without selecting an item, returning failure. 94Exit without selecting an item, returning failure.
100.TP 95.TP
101.B Control\-y 96.B Control\-y
102Paste the current X selection into the input field. 97Paste 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).
diff --git a/dmenu.c b/dmenu.c
index 12902ac..7dfc2d3 100644
--- a/dmenu.c
+++ b/dmenu.c
@@ -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);
38static void insert(const char *s, ssize_t n); 35static void insert(const char *s, ssize_t n);
39static void keypress(XKeyEvent *e); 36static void keypress(XKeyEvent *e);
40static void match(void); 37static void match(void);
41static void paste(Atom atom); 38static void paste(void);
42static void readstdin(void); 39static void readstdin(void);
43static void run(void); 40static void run(void);
44static void setup(void); 41static void setup(void);
45static void usage(void); 42static void usage(void);
46 43
47static char *prompt;
48static char text[4096]; 44static char text[4096];
49static int screen;
50static size_t cursor = 0; 45static size_t cursor = 0;
46static const char *prompt = NULL;
47static const char *normbgcolor = "#cccccc";
48static const char *normfgcolor = "#000000";
49static const char *selbgcolor = "#0066ff";
50static const char *selfgcolor = "#ffffff";
51static unsigned int inputw = 0; 51static unsigned int inputw = 0;
52static unsigned int lines = 0; 52static unsigned int lines = 0;
53static unsigned int mw, mh; 53static unsigned int mw, mh;
54static unsigned int promptw = 0;
55static unsigned long normcol[ColLast]; 54static unsigned long normcol[ColLast];
56static unsigned long selcol[ColLast]; 55static unsigned long selcol[ColLast];
57static Atom utf8; 56static Atom utf8;
58static Bool topbar = True; 57static Bool topbar = True;
59static DC dc; 58static DC *dc;
60static Item *allitems, *matches; 59static Item *allitems, *matches;
61static Item *curr, *prev, *next, *sel; 60static Item *curr, *prev, *next, *sel;
62static Window root, win; 61static Window root, win;
@@ -67,7 +66,7 @@ static void (*calcoffsets)(void) = calcoffsetsh;
67 66
68void 67void
69appenditem(Item *item, Item **list, Item **last) { 68appenditem(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
80calcoffsetsh(void) { 79calcoffsetsh(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
104char * 102char *
105cistrstr(const char *s, const char *sub) { 103cistrstr(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
126void 112void
127drawmenu(void) { 113drawmenu(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
155void 138void
156drawmenuh(void) { 139drawmenuh(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
177void 157void
178drawmenuv(void) { 158drawmenuv(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
196void 169void
@@ -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
420void 394void
421paste(Atom atom) 395paste(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
435void 408void
436readstdin(void) { 409readstdin(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
460run(void) { 431run(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
483void 454void
484setup(void) { 455setup(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
539void 513void
540usage(void) { 514usage(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();
diff --git a/dmenu_path b/dmenu_path
index 7896a9e..a9ddd47 100755
--- a/dmenu_path
+++ b/dmenu_path
@@ -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"
24fi 24fi
25 25