aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile15
-rw-r--r--common.c129
-rw-r--r--dinput.c230
-rw-r--r--dmenu.c251
-rw-r--r--dmenu.h30
5 files changed, 215 insertions, 440 deletions
diff --git a/Makefile b/Makefile
index 7274923..0d16e38 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
3 3
4include config.mk 4include config.mk
5 5
6SRC = dinput.c dmenu.c common.c 6SRC = dmenu.c
7OBJ = ${SRC:.c=.o} 7OBJ = ${SRC:.c=.o}
8 8
9all: options dinput dmenu 9all: options dinput dmenu
@@ -24,17 +24,13 @@ config.h:
24 @echo creating $@ from config.def.h 24 @echo creating $@ from config.def.h
25 @cp config.def.h $@ 25 @cp config.def.h $@
26 26
27dinput: dinput.o common.o 27dmenu: ${OBJ}
28 @echo CC -o $@
29 @${CC} -o $@ $+ ${LDFLAGS}
30
31dmenu: dmenu.o common.o
32 @echo CC -o $@ 28 @echo CC -o $@
33 @${CC} -o $@ $+ ${LDFLAGS} 29 @${CC} -o $@ $+ ${LDFLAGS}
34 30
35clean: 31clean:
36 @echo cleaning 32 @echo cleaning
37 @rm -f dinput dmenu ${OBJ} dmenu-${VERSION}.tar.gz 33 @rm -f dmenu ${OBJ} dmenu-${VERSION}.tar.gz
38 34
39dist: clean 35dist: clean
40 @echo creating dist tarball 36 @echo creating dist tarball
@@ -47,8 +43,7 @@ dist: clean
47install: all 43install: all
48 @echo installing executable file to ${DESTDIR}${PREFIX}/bin 44 @echo installing executable file to ${DESTDIR}${PREFIX}/bin
49 @mkdir -p ${DESTDIR}${PREFIX}/bin 45 @mkdir -p ${DESTDIR}${PREFIX}/bin
50 @cp -f dinput dmenu dmenu_path dmenu_run ${DESTDIR}${PREFIX}/bin 46 @cp -f dmenu dmenu_path dmenu_run ${DESTDIR}${PREFIX}/bin
51 @chmod 755 ${DESTDIR}${PREFIX}/bin/dinput
52 @chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu 47 @chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu
53 @chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_path 48 @chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_path
54 @chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_run 49 @chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_run
@@ -60,7 +55,7 @@ install: all
60uninstall: 55uninstall:
61 @echo removing executable file from ${DESTDIR}${PREFIX}/bin 56 @echo removing executable file from ${DESTDIR}${PREFIX}/bin
62 @rm -f ${DESTDIR}${PREFIX}/bin/dmenu ${DESTDIR}${PREFIX}/bin/dmenu_path 57 @rm -f ${DESTDIR}${PREFIX}/bin/dmenu ${DESTDIR}${PREFIX}/bin/dmenu_path
63 @rm -f ${DESTDIR}${PREFIX}/bin/dinput ${DESTDIR}${PREFIX}/bin/dmenu_run 58 @rm -f ${DESTDIR}${PREFIX}/bin/dmenu_run
64 @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 59 @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
65 @rm -f ${DESTDIR}${MANPREFIX}/man1/dmenu.1 60 @rm -f ${DESTDIR}${MANPREFIX}/man1/dmenu.1
66 61
diff --git a/common.c b/common.c
deleted file mode 100644
index 2d19aee..0000000
--- a/common.c
+++ /dev/null
@@ -1,129 +0,0 @@
1/* See LICENSE file for copyright and license details. */
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include <X11/keysym.h>
6#ifdef XINERAMA
7#include <X11/extensions/Xinerama.h>
8#endif
9#include "dmenu.h"
10
11/* variables */
12char *prompt = NULL;
13char text[4096] = "";
14int promptw = 0;
15int screen;
16unsigned int numlockmask = 0;
17unsigned int mw, mh;
18unsigned long normcol[ColLast];
19unsigned long selcol[ColLast];
20Bool topbar = True;
21DC dc;
22Display *dpy;
23Window win, root;
24
25void
26grabkeyboard(void) {
27 unsigned int len;
28
29 for(len = 1000; len; len--) {
30 if(XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime)
31 == GrabSuccess)
32 return;
33 usleep(1000);
34 }
35 exit(EXIT_FAILURE);
36}
37
38void
39run(void) {
40 XEvent ev;
41
42 /* main event loop */
43 XSync(dpy, False);
44 while(!XNextEvent(dpy, &ev))
45 switch(ev.type) {
46 case KeyPress:
47 kpress(&ev.xkey);
48 break;
49 case Expose:
50 if(ev.xexpose.count == 0)
51 drawbar();
52 break;
53 case VisibilityNotify:
54 if(ev.xvisibility.state != VisibilityUnobscured)
55 XRaiseWindow(dpy, win);
56 break;
57 }
58 exit(EXIT_FAILURE);
59}
60
61void
62setup(unsigned int lines) {
63 int i, j, x, y;
64#if XINERAMA
65 int n;
66 XineramaScreenInfo *info = NULL;
67#endif
68 XModifierKeymap *modmap;
69 XSetWindowAttributes wa;
70
71 /* init modifier map */
72 modmap = XGetModifierMapping(dpy);
73 for(i = 0; i < 8; i++)
74 for(j = 0; j < modmap->max_keypermod; j++) {
75 if(modmap->modifiermap[i * modmap->max_keypermod + j]
76 == XKeysymToKeycode(dpy, XK_Num_Lock))
77 numlockmask = (1 << i);
78 }
79 XFreeModifiermap(modmap);
80
81 dc.dpy = dpy;
82 normcol[ColBG] = getcolor(&dc, normbgcolor);
83 normcol[ColFG] = getcolor(&dc, normfgcolor);
84 selcol[ColBG] = getcolor(&dc, selbgcolor);
85 selcol[ColFG] = getcolor(&dc, selfgcolor);
86 initfont(&dc, font);
87
88 /* input window */
89 wa.override_redirect = True;
90 wa.background_pixmap = ParentRelative;
91 wa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
92
93 /* input window geometry */
94 mh = (dc.font.height + 2) * (lines + 1);
95#if XINERAMA
96 if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) {
97 i = 0;
98 if(n > 1) {
99 int di;
100 unsigned int dui;
101 Window dummy;
102 if(XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui))
103 for(i = 0; i < n; i++)
104 if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height))
105 break;
106 }
107 x = info[i].x_org;
108 y = topbar ? info[i].y_org : info[i].y_org + info[i].height - mh;
109 mw = info[i].width;
110 XFree(info);
111 }
112 else
113#endif
114 {
115 x = 0;
116 y = topbar ? 0 : DisplayHeight(dpy, screen) - mh;
117 mw = DisplayWidth(dpy, screen);
118 }
119
120 win = XCreateWindow(dpy, root, x, y, mw, mh, 0,
121 DefaultDepth(dpy, screen), CopyFromParent,
122 DefaultVisual(dpy, screen),
123 CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
124
125 setupdraw(&dc, win);
126 if(prompt)
127 promptw = MIN(textw(&dc, prompt), mw / 5);
128 XMapRaised(dpy, win);
129}
diff --git a/dinput.c b/dinput.c
deleted file mode 100644
index 4bbc7bc..0000000
--- a/dinput.c
+++ /dev/null
@@ -1,230 +0,0 @@
1/* See LICENSE file for copyright and license details. */
2#include <ctype.h>
3#include <locale.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <X11/keysym.h>
8#include <X11/Xlib.h>
9#include <X11/Xutil.h>
10#include "dmenu.h"
11
12/* forward declarations */
13static void cleanup(void);
14
15/* variables */
16static size_t cursor = 0;
17
18void
19cleanup(void) {
20 cleanupdraw(&dc);
21 XDestroyWindow(dpy, win);
22 XUngrabKeyboard(dpy, CurrentTime);
23 XCloseDisplay(dpy);
24}
25
26void
27drawbar(void)
28{
29 dc.x = 0;
30 dc.y = 0;
31 dc.w = mw;
32 dc.h = mh;
33 drawbox(&dc, normcol);
34 /* print prompt? */
35 if(prompt) {
36 dc.w = promptw;
37 drawbox(&dc, selcol);
38 drawtext(&dc, prompt, selcol);
39 dc.x += dc.w;
40 }
41 dc.w = mw - dc.x;
42 drawtext(&dc, text, normcol);
43 drawline(&dc, textnw(&dc, text, cursor) + dc.font.height/2, 2, 1,
44 dc.font.height-2, normcol);
45 commitdraw(&dc, win);
46}
47
48void
49kpress(XKeyEvent *e) {
50 char buf[sizeof text];
51 int num;
52 unsigned int i, len;
53 KeySym ksym;
54
55 len = strlen(text);
56 num = XLookupString(e, buf, sizeof buf, &ksym, NULL);
57 if(ksym == XK_KP_Enter)
58 ksym = XK_Return;
59 else if(ksym >= XK_KP_0 && ksym <= XK_KP_9)
60 ksym = (ksym - XK_KP_0) + XK_0;
61 else if(IsFunctionKey(ksym) || IsKeypadKey(ksym)
62 || IsMiscFunctionKey(ksym) || IsPFKey(ksym)
63 || IsPrivateKeypadKey(ksym))
64 return;
65 /* first check if a control mask is omitted */
66 if(e->state & ControlMask) {
67 switch(tolower(ksym)) {
68 default:
69 return;
70 case XK_a:
71 ksym = XK_Home;
72 break;
73 case XK_b:
74 ksym = XK_Left;
75 break;
76 case XK_c:
77 ksym = XK_Escape;
78 break;
79 case XK_e:
80 ksym = XK_End;
81 break;
82 case XK_f:
83 ksym = XK_Right;
84 break;
85 case XK_h:
86 ksym = XK_BackSpace;
87 break;
88 case XK_j:
89 case XK_m:
90 ksym = XK_Return;
91 break;
92 case XK_k:
93 text[cursor] = '\0';
94 break;
95 case XK_u:
96 memmove(text, text + cursor, sizeof text - cursor + 1);
97 cursor = 0;
98 break;
99 case XK_w:
100 if(cursor > 0) {
101 i = cursor;
102 while(i-- > 0 && text[i] == ' ');
103 while(i-- > 0 && text[i] != ' ');
104 memmove(text + i + 1, text + cursor, sizeof text - cursor + 1);
105 cursor = i + 1;
106 }
107 break;
108 case XK_y:
109 {
110 FILE *fp;
111 char *s;
112 if(!(fp = popen("sselp", "r")))
113 eprint("cannot popen sselp\n");
114 s = fgets(buf, sizeof buf, fp);
115 pclose(fp);
116 if(s == NULL)
117 return;
118 }
119 num = strlen(buf);
120 if(num && buf[num-1] == '\n')
121 buf[--num] = '\0';
122 break;
123 }
124 }
125 switch(ksym) {
126 default:
127 num = MIN(num, sizeof text - cursor);
128 if(num && !iscntrl((int) buf[0])) {
129 memmove(text + cursor + num, text + cursor, sizeof text - cursor - num);
130 memcpy(text + cursor, buf, num);
131 cursor += num;
132 }
133 break;
134 case XK_BackSpace:
135 if(cursor == 0)
136 return;
137 for(i = 1; cursor - i > 0 && !IS_UTF8_1ST_CHAR(text[cursor - i]); i++);
138 memmove(text + cursor - i, text + cursor, sizeof text - cursor + i);
139 cursor -= i;
140 break;
141 case XK_Delete:
142 if(cursor == len)
143 return;
144 for(i = 1; cursor + i < len && !IS_UTF8_1ST_CHAR(text[cursor + i]); i++);
145 memmove(text + cursor, text + cursor + i, sizeof text - cursor);
146 break;
147 case XK_End:
148 cursor = len;
149 break;
150 case XK_Escape:
151 exit(EXIT_FAILURE);
152 case XK_Home:
153 cursor = 0;
154 break;
155 case XK_Left:
156 if(cursor == 0)
157 return;
158 while(cursor-- > 0 && !IS_UTF8_1ST_CHAR(text[cursor]));
159 break;
160 case XK_Return:
161 fprintf(stdout, "%s", text);
162 fflush(stdout);
163 exit(EXIT_SUCCESS);
164 case XK_Right:
165 if(cursor == len)
166 return;
167 while(cursor++ < len && !IS_UTF8_1ST_CHAR(text[cursor]));
168 break;
169 }
170 drawbar();
171}
172
173int
174main(int argc, char *argv[]) {
175 unsigned int i;
176
177 /* command line args */
178 progname = "dinput";
179 for(i = 1; i < argc; i++)
180 if(!strcmp(argv[i], "-i"))
181 ; /* ignore flag */
182 else if(!strcmp(argv[i], "-b"))
183 topbar = False;
184 else if(!strcmp(argv[i], "-l"))
185 i++; /* ignore flag */
186 else if(!strcmp(argv[i], "-fn")) {
187 if(++i < argc) font = argv[i];
188 }
189 else if(!strcmp(argv[i], "-nb")) {
190 if(++i < argc) normbgcolor = argv[i];
191 }
192 else if(!strcmp(argv[i], "-nf")) {
193 if(++i < argc) normfgcolor = argv[i];
194 }
195 else if(!strcmp(argv[i], "-p")) {
196 if(++i < argc) prompt = argv[i];
197 }
198 else if(!strcmp(argv[i], "-sb")) {
199 if(++i < argc) selbgcolor = argv[i];
200 }
201 else if(!strcmp(argv[i], "-sf")) {
202 if(++i < argc) selfgcolor = argv[i];
203 }
204 else if(!strcmp(argv[i], "-v")) {
205 printf("dinput-"VERSION", © 2006-2010 dmenu engineers, see LICENSE for details\n");
206 exit(EXIT_SUCCESS);
207 }
208 else if(!*text) {
209 strncpy(text, argv[i], sizeof text);
210 cursor = strlen(text);
211 }
212 else {
213 fputs("usage: dinput [-b] [-fn <font>] [-nb <color>] [-nf <color>]\n"
214 " [-p <prompt>] [-sb <color>] [-sf <color>] [-v] [<text>]\n", stderr);
215 exit(EXIT_FAILURE);
216 }
217 if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
218 fprintf(stderr, "dinput: warning: no locale support\n");
219 if(!(dpy = XOpenDisplay(NULL)))
220 eprint("cannot open display\n");
221 if(atexit(&cleanup) != 0)
222 eprint("cannot register cleanup\n");
223 screen = DefaultScreen(dpy);
224 root = RootWindow(dpy, screen);
225
226 grabkeyboard();
227 setup(0);
228 run();
229 return 0;
230}
diff --git a/dmenu.c b/dmenu.c
index 9386e06..1fdf7f5 100644
--- a/dmenu.c
+++ b/dmenu.c
@@ -8,7 +8,16 @@
8#include <X11/keysym.h> 8#include <X11/keysym.h>
9#include <X11/Xlib.h> 9#include <X11/Xlib.h>
10#include <X11/Xutil.h> 10#include <X11/Xutil.h>
11#include "dmenu.h" 11#ifdef XINERAMA
12#include <X11/extensions/Xinerama.h>
13#endif
14#include <draw.h>
15#include "config.h"
16
17#define INRECT(x,y,rx,ry,rw,rh) ((rx) < (x) && (x) < (rx)+(rw) && (ry) < (y) && (y) < (ry)+(rh))
18#define MIN(a,b) ((a) < (b) ? (a) : (b))
19#define MAX(a,b) ((a) > (b) ? (a) : (b))
20#define IS_UTF8_1ST_CHAR(c) (((c) & 0xc0) == 0xc0 || ((c) & 0x80) == 0x00)
12 21
13typedef struct Item Item; 22typedef struct Item Item;
14struct Item { 23struct Item {
@@ -17,30 +26,46 @@ struct Item {
17 Item *left, *right; /* traverses items matching current search pattern */ 26 Item *left, *right; /* traverses items matching current search pattern */
18}; 27};
19 28
20/* forward declarations */
21static void appenditem(Item *i, Item **list, Item **last); 29static void appenditem(Item *i, Item **list, Item **last);
22static void calcoffsetsh(void); 30static void calcoffsetsh(void);
23static void calcoffsetsv(void); 31static void calcoffsetsv(void);
24static char *cistrstr(const char *s, const char *sub); 32static char *cistrstr(const char *s, const char *sub);
25static void cleanup(void); 33static void cleanup(void);
26static void dinput(void);
27static void drawitem(const char *s, unsigned long col[ColLast]); 34static void drawitem(const char *s, unsigned long col[ColLast]);
35static void drawmenu(void);
28static void drawmenuh(void); 36static void drawmenuh(void);
29static void drawmenuv(void); 37static void drawmenuv(void);
38static void grabkeyboard(void);
39static void keypress(XKeyEvent *e);
30static void match(void); 40static void match(void);
31static void readstdin(void); 41static void readstdin(void);
42static void run(void);
43static void setup(void);
32 44
33/* variables */
34static char **argp = NULL; 45static char **argp = NULL;
35static char *maxname = NULL; 46static char *maxname = NULL;
47static char *prompt;
48static char text[4096];
49static int promptw;
50static int screen;
51static size_t cur = 0;
36static unsigned int cmdw = 0; 52static unsigned int cmdw = 0;
37static unsigned int lines = 0; 53static unsigned int lines = 0;
54static unsigned int numlockmask;
55static unsigned int mw, mh;
56static unsigned long normcol[ColLast];
57static unsigned long selcol[ColLast];
58static Bool topbar = True;
59static DC dc;
60static Display *dpy;
38static Item *allitems = NULL; /* first of all items */ 61static Item *allitems = NULL; /* first of all items */
39static Item *item = NULL; /* first of pattern matching items */ 62static Item *item = NULL; /* first of pattern matching items */
40static Item *sel = NULL; 63static Item *sel = NULL;
41static Item *next = NULL; 64static Item *next = NULL;
42static Item *prev = NULL; 65static Item *prev = NULL;
43static Item *curr = NULL; 66static Item *curr = NULL;
67static Window win, root;
68
44static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; 69static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
45static char *(*fstrstr)(const char *, const char *) = strstr; 70static char *(*fstrstr)(const char *, const char *) = strstr;
46static void (*calcoffsets)(void) = calcoffsetsh; 71static void (*calcoffsets)(void) = calcoffsetsh;
@@ -120,16 +145,18 @@ cleanup(void) {
120} 145}
121 146
122void 147void
123dinput(void) { 148drawitem(const char *s, unsigned long col[ColLast]) {
124 cleanup(); 149 const char *p;
125 argp[0] = "dinput"; 150 unsigned int w = textnw(&dc, text, strlen(text));
126 argp[1] = text; 151
127 execvp("dinput", argp); 152 drawbox(&dc, col);
128 eprint("cannot exec dinput\n"); 153 drawtext(&dc, s, col);
154 for(p = fstrstr(s, text); *text && (p = fstrstr(p, text)); p++)
155 drawline(&dc, textnw(&dc, s, p-s) + dc.h/2 - 1, dc.h-2, w, 1, col);
129} 156}
130 157
131void 158void
132drawbar(void) { 159drawmenu(void) {
133 dc.x = 0; 160 dc.x = 0;
134 dc.y = 0; 161 dc.y = 0;
135 dc.w = mw; 162 dc.w = mw;
@@ -149,6 +176,7 @@ drawbar(void) {
149 if(cmdw && item && lines == 0) 176 if(cmdw && item && lines == 0)
150 dc.w = cmdw; 177 dc.w = cmdw;
151 drawtext(&dc, text, normcol); 178 drawtext(&dc, text, normcol);
179 drawline(&dc, textnw(&dc, text, cur) + dc.h/2 - 2, 2, 1, dc.h-4, normcol);
152 if(lines > 0) 180 if(lines > 0)
153 drawmenuv(); 181 drawmenuv();
154 else if(curr) 182 else if(curr)
@@ -157,17 +185,6 @@ drawbar(void) {
157} 185}
158 186
159void 187void
160drawitem(const char *s, unsigned long col[ColLast]) {
161 const char *p;
162 unsigned int w = textnw(&dc, text, strlen(text));
163
164 drawbox(&dc, col);
165 drawtext(&dc, s, col);
166 for(p = fstrstr(s, text); *text && (p = fstrstr(p, text)); p++)
167 drawline(&dc, textnw(&dc, s, p-s) + dc.h/2 - 1, dc.h-2, w, 1, col);
168}
169
170void
171drawmenuh(void) { 188drawmenuh(void) {
172 Item *i; 189 Item *i;
173 190
@@ -202,7 +219,19 @@ drawmenuv(void) {
202} 219}
203 220
204void 221void
205kpress(XKeyEvent *e) { 222grabkeyboard(void) {
223 unsigned int n;
224
225 for(n = 0; n < 1000; n++) {
226 if(!XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime))
227 return;
228 usleep(1000);
229 }
230 exit(EXIT_FAILURE);
231}
232
233void
234keypress(XKeyEvent *e) {
206 char buf[sizeof text]; 235 char buf[sizeof text];
207 int num; 236 int num;
208 unsigned int i, len; 237 unsigned int i, len;
@@ -248,6 +277,9 @@ kpress(XKeyEvent *e) {
248 case XK_m: 277 case XK_m:
249 ksym = XK_Return; 278 ksym = XK_Return;
250 break; 279 break;
280 case XK_k:
281 text[cur] = '\0';
282 break;
251 case XK_n: 283 case XK_n:
252 ksym = XK_Down; 284 ksym = XK_Down;
253 break; 285 break;
@@ -255,38 +287,67 @@ kpress(XKeyEvent *e) {
255 ksym = XK_Up; 287 ksym = XK_Up;
256 break; 288 break;
257 case XK_u: 289 case XK_u:
258 text[0] = '\0'; 290 memmove(text, text + cur, sizeof text - cur + 1);
291 cur = 0;
259 match(); 292 match();
260 break; 293 break;
261 case XK_w: 294 case XK_w:
262 if(len == 0) 295 if(cur == 0)
263 return; 296 return;
264 i = len; 297 i = cur;
265 while(i-- > 0 && text[i] == ' '); 298 while(i-- > 0 && text[i] == ' ');
266 while(i-- > 0 && text[i] != ' '); 299 while(i-- > 0 && text[i] != ' ');
267 text[++i] = '\0'; 300 memmove(text + i + 1, text + cur, sizeof text - cur + 1);
301 cur = i + 1;
268 match(); 302 match();
269 break; 303 break;
304 case XK_y:
305 {
306 FILE *fp;
307 char *s;
308 if(!(fp = fopen("sselp", "r")))
309 eprint("cannot popen sselp\n");
310 s = fgets(buf, sizeof buf, fp);
311 fclose(fp);
312 if(!s)
313 return;
314 }
315 num = strlen(buf);
316 if(num && buf[num-1] == '\n')
317 buf[--num] = '\0';
318 break;
270 } 319 }
271 } 320 }
272 switch(ksym) { 321 switch(ksym) {
273 default: 322 default:
274 num = MIN(num, sizeof text); 323 num = MIN(num, sizeof text);
275 if(num && !iscntrl((int) buf[0])) { 324 if(num && !iscntrl((int) buf[0])) {
276 memcpy(text + len, buf, num + 1); 325 memmove(text + cur + num, text + cur, sizeof text - cur - num);
277 len += num; 326 memcpy(text + cur, buf, num);
327 cur += num;
278 match(); 328 match();
279 } 329 }
280 break; 330 break;
281 case XK_BackSpace: 331 case XK_BackSpace:
282 if(len == 0) 332 if(cur == 0)
283 return; 333 return;
284 for(i = 1; len - i > 0 && !IS_UTF8_1ST_CHAR(text[len - i]); i++); 334 for(i = 1; len - i > 0 && !IS_UTF8_1ST_CHAR(text[cur - i]); i++);
285 len -= i; 335 memmove(text + cur - i, text + cur, sizeof text - cur + i);
286 text[len] = '\0'; 336 cur -= i;
337 match();
338 break;
339 case XK_Delete:
340 if(cur == len)
341 return;
342 for(i = 1; cur + i < len && !IS_UTF8_1ST_CHAR(text[cur + i]); i++);
343 memmove(text + cur, text + cur + i, sizeof text - cur);
287 match(); 344 match();
288 break; 345 break;
289 case XK_End: 346 case XK_End:
347 if(cur < len) {
348 cur = len;
349 break;
350 }
290 while(next) { 351 while(next) {
291 sel = curr = next; 352 sel = curr = next;
292 calcoffsets(); 353 calcoffsets();
@@ -297,10 +358,20 @@ kpress(XKeyEvent *e) {
297 case XK_Escape: 358 case XK_Escape:
298 exit(EXIT_FAILURE); 359 exit(EXIT_FAILURE);
299 case XK_Home: 360 case XK_Home:
361 if(sel == item) {
362 cur = 0;
363 break;
364 }
300 sel = curr = item; 365 sel = curr = item;
301 calcoffsets(); 366 calcoffsets();
302 break; 367 break;
303 case XK_Left: 368 case XK_Left:
369 if(cur > 0 && (!sel || !sel->left || lines > 0)) {
370 while(cur-- > 0 && !IS_UTF8_1ST_CHAR(text[cur]));
371 break;
372 }
373 if(lines > 0)
374 return;
304 case XK_Up: 375 case XK_Up:
305 if(!sel || !sel->left) 376 if(!sel || !sel->left)
306 return; 377 return;
@@ -323,12 +394,16 @@ kpress(XKeyEvent *e) {
323 calcoffsets(); 394 calcoffsets();
324 break; 395 break;
325 case XK_Return: 396 case XK_Return:
326 if(e->state & ShiftMask) 397 fprintf(stdout, "%s", ((e->state & ShiftMask) || sel) ? sel->text : text);
327 dinput();
328 fprintf(stdout, "%s", sel ? sel->text : text);
329 fflush(stdout); 398 fflush(stdout);
330 exit(EXIT_SUCCESS); 399 exit(EXIT_SUCCESS);
331 case XK_Right: 400 case XK_Right:
401 if(cur < len) {
402 while(cur++ < len && !IS_UTF8_1ST_CHAR(text[cur]));
403 break;
404 }
405 if(lines > 0)
406 return;
332 case XK_Down: 407 case XK_Down:
333 if(!sel || !sel->right) 408 if(!sel || !sel->right)
334 return; 409 return;
@@ -339,12 +414,14 @@ kpress(XKeyEvent *e) {
339 } 414 }
340 break; 415 break;
341 case XK_Tab: 416 case XK_Tab:
342 if(sel) 417 if(!sel)
343 strncpy(text, sel->text, sizeof text); 418 return;
344 dinput(); 419 strncpy(text, sel->text, sizeof text);
420 cur = strlen(text);
421 match();
345 break; 422 break;
346 } 423 }
347 drawbar(); 424 drawmenu();
348} 425}
349 426
350void 427void
@@ -413,6 +490,98 @@ readstdin(void) {
413 } 490 }
414} 491}
415 492
493void
494run(void) {
495 XEvent ev;
496
497 XSync(dpy, False);
498 while(!XNextEvent(dpy, &ev))
499 switch(ev.type) {
500 case Expose:
501 if(ev.xexpose.count == 0)
502 drawmenu();
503 break;
504 case KeyPress:
505 keypress(&ev.xkey);
506 break;
507 case VisibilityNotify:
508 if(ev.xvisibility.state != VisibilityUnobscured)
509 XRaiseWindow(dpy, win);
510 break;
511 }
512 exit(EXIT_FAILURE);
513}
514
515void
516setup(void) {
517 int i, j, x, y;
518#if XINERAMA
519 int n;
520 XineramaScreenInfo *info = NULL;
521#endif
522 XModifierKeymap *modmap;
523 XSetWindowAttributes wa;
524
525 /* init modifier map */
526 modmap = XGetModifierMapping(dpy);
527 for(i = 0; i < 8; i++)
528 for(j = 0; j < modmap->max_keypermod; j++) {
529 if(modmap->modifiermap[i * modmap->max_keypermod + j]
530 == XKeysymToKeycode(dpy, XK_Num_Lock))
531 numlockmask = (1 << i);
532 }
533 XFreeModifiermap(modmap);
534
535 dc.dpy = dpy;
536 normcol[ColBG] = getcolor(&dc, normbgcolor);
537 normcol[ColFG] = getcolor(&dc, normfgcolor);
538 selcol[ColBG] = getcolor(&dc, selbgcolor);
539 selcol[ColFG] = getcolor(&dc, selfgcolor);
540 initfont(&dc, font);
541
542 /* input window */
543 wa.override_redirect = True;
544 wa.background_pixmap = ParentRelative;
545 wa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
546
547 /* input window geometry */
548 mh = (dc.font.height + 2) * (lines + 1);
549#if XINERAMA
550 if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) {
551 i = 0;
552 if(n > 1) {
553 int di;
554 unsigned int dui;
555 Window dummy;
556 if(XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui))
557 for(i = 0; i < n; i++)
558 if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height))
559 break;
560 }
561 x = info[i].x_org;
562 y = topbar ? info[i].y_org : info[i].y_org + info[i].height - mh;
563 mw = info[i].width;
564 XFree(info);
565 }
566 else
567#endif
568 {
569 x = 0;
570 y = topbar ? 0 : DisplayHeight(dpy, screen) - mh;
571 mw = DisplayWidth(dpy, screen);
572 }
573
574 win = XCreateWindow(dpy, root, x, y, mw, mh, 0,
575 DefaultDepth(dpy, screen), CopyFromParent,
576 DefaultVisual(dpy, screen),
577 CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
578
579 setupdraw(&dc, win);
580 if(prompt)
581 promptw = MIN(textw(&dc, prompt), mw / 5);
582 XMapRaised(dpy, win);
583}
584
416int 585int
417main(int argc, char *argv[]) { 586main(int argc, char *argv[]) {
418 unsigned int i; 587 unsigned int i;
@@ -472,7 +641,7 @@ main(int argc, char *argv[]) {
472 641
473 readstdin(); 642 readstdin();
474 grabkeyboard(); 643 grabkeyboard();
475 setup(lines); 644 setup();
476 if(maxname) 645 if(maxname)
477 cmdw = MIN(textw(&dc, maxname), mw / 3); 646 cmdw = MIN(textw(&dc, maxname), mw / 3);
478 match(); 647 match();
diff --git a/dmenu.h b/dmenu.h
deleted file mode 100644
index 4cc13f4..0000000
--- a/dmenu.h
+++ /dev/null
@@ -1,30 +0,0 @@
1#include <X11/Xlib.h>
2#include <draw.h>
3#include "config.h"
4
5/* macros */
6#define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH))
7#define MIN(a, b) ((a) < (b) ? (a) : (b))
8#define MAX(a, b) ((a) > (b) ? (a) : (b))
9#define IS_UTF8_1ST_CHAR(c) ((((c) & 0xc0) == 0xc0) || !((c) & 0x80))
10
11/* forward declarations */
12void drawbar(void);
13void grabkeyboard(void);
14void kpress(XKeyEvent *e);
15void run(void);
16void setup(unsigned int lines);
17
18/* variables */
19extern char *prompt;
20extern char text[4096];
21extern int promptw;
22extern int screen;
23extern unsigned int numlockmask;
24extern unsigned int mw, mh;
25extern unsigned long normcol[ColLast];
26extern unsigned long selcol[ColLast];
27extern Bool topbar;
28extern DC dc;
29extern Display *dpy;
30extern Window win, root;