diff options
author | Connor Lane Smith <cls@lubutu.com> | 2010-07-30 13:40:56 +0100 |
---|---|---|
committer | Connor Lane Smith <cls@lubutu.com> | 2010-07-30 13:40:56 +0100 |
commit | 7d5fe17391fefd978eab281a6cbebe2aa601e9ce (patch) | |
tree | 07d003a35241fb2c24e66fc30498c16ccdb39be2 | |
parent | 7f36736d11418b0b11d02da8aa0cb663406706c2 (diff) |
merged dmenu & dinput (clunky interface)
-rw-r--r-- | Makefile | 15 | ||||
-rw-r--r-- | common.c | 129 | ||||
-rw-r--r-- | dinput.c | 230 | ||||
-rw-r--r-- | dmenu.c | 251 | ||||
-rw-r--r-- | dmenu.h | 30 |
5 files changed, 215 insertions, 440 deletions
@@ -3,7 +3,7 @@ | |||
3 | 3 | ||
4 | include config.mk | 4 | include config.mk |
5 | 5 | ||
6 | SRC = dinput.c dmenu.c common.c | 6 | SRC = dmenu.c |
7 | OBJ = ${SRC:.c=.o} | 7 | OBJ = ${SRC:.c=.o} |
8 | 8 | ||
9 | all: options dinput dmenu | 9 | all: 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 | ||
27 | dinput: dinput.o common.o | 27 | dmenu: ${OBJ} |
28 | @echo CC -o $@ | ||
29 | @${CC} -o $@ $+ ${LDFLAGS} | ||
30 | |||
31 | dmenu: dmenu.o common.o | ||
32 | @echo CC -o $@ | 28 | @echo CC -o $@ |
33 | @${CC} -o $@ $+ ${LDFLAGS} | 29 | @${CC} -o $@ $+ ${LDFLAGS} |
34 | 30 | ||
35 | clean: | 31 | clean: |
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 | ||
39 | dist: clean | 35 | dist: clean |
40 | @echo creating dist tarball | 36 | @echo creating dist tarball |
@@ -47,8 +43,7 @@ dist: clean | |||
47 | install: all | 43 | install: 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 | |||
60 | uninstall: | 55 | uninstall: |
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 */ | ||
12 | char *prompt = NULL; | ||
13 | char text[4096] = ""; | ||
14 | int promptw = 0; | ||
15 | int screen; | ||
16 | unsigned int numlockmask = 0; | ||
17 | unsigned int mw, mh; | ||
18 | unsigned long normcol[ColLast]; | ||
19 | unsigned long selcol[ColLast]; | ||
20 | Bool topbar = True; | ||
21 | DC dc; | ||
22 | Display *dpy; | ||
23 | Window win, root; | ||
24 | |||
25 | void | ||
26 | grabkeyboard(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 | |||
38 | void | ||
39 | run(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 | |||
61 | void | ||
62 | setup(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 */ | ||
13 | static void cleanup(void); | ||
14 | |||
15 | /* variables */ | ||
16 | static size_t cursor = 0; | ||
17 | |||
18 | void | ||
19 | cleanup(void) { | ||
20 | cleanupdraw(&dc); | ||
21 | XDestroyWindow(dpy, win); | ||
22 | XUngrabKeyboard(dpy, CurrentTime); | ||
23 | XCloseDisplay(dpy); | ||
24 | } | ||
25 | |||
26 | void | ||
27 | drawbar(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 | |||
48 | void | ||
49 | kpress(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 | |||
173 | int | ||
174 | main(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 | } | ||
@@ -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 | ||
13 | typedef struct Item Item; | 22 | typedef struct Item Item; |
14 | struct Item { | 23 | struct 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 */ | ||
21 | static void appenditem(Item *i, Item **list, Item **last); | 29 | static void appenditem(Item *i, Item **list, Item **last); |
22 | static void calcoffsetsh(void); | 30 | static void calcoffsetsh(void); |
23 | static void calcoffsetsv(void); | 31 | static void calcoffsetsv(void); |
24 | static char *cistrstr(const char *s, const char *sub); | 32 | static char *cistrstr(const char *s, const char *sub); |
25 | static void cleanup(void); | 33 | static void cleanup(void); |
26 | static void dinput(void); | ||
27 | static void drawitem(const char *s, unsigned long col[ColLast]); | 34 | static void drawitem(const char *s, unsigned long col[ColLast]); |
35 | static void drawmenu(void); | ||
28 | static void drawmenuh(void); | 36 | static void drawmenuh(void); |
29 | static void drawmenuv(void); | 37 | static void drawmenuv(void); |
38 | static void grabkeyboard(void); | ||
39 | static void keypress(XKeyEvent *e); | ||
30 | static void match(void); | 40 | static void match(void); |
31 | static void readstdin(void); | 41 | static void readstdin(void); |
42 | static void run(void); | ||
43 | static void setup(void); | ||
32 | 44 | ||
33 | /* variables */ | ||
34 | static char **argp = NULL; | 45 | static char **argp = NULL; |
35 | static char *maxname = NULL; | 46 | static char *maxname = NULL; |
47 | static char *prompt; | ||
48 | static char text[4096]; | ||
49 | static int promptw; | ||
50 | static int screen; | ||
51 | static size_t cur = 0; | ||
36 | static unsigned int cmdw = 0; | 52 | static unsigned int cmdw = 0; |
37 | static unsigned int lines = 0; | 53 | static unsigned int lines = 0; |
54 | static unsigned int numlockmask; | ||
55 | static unsigned int mw, mh; | ||
56 | static unsigned long normcol[ColLast]; | ||
57 | static unsigned long selcol[ColLast]; | ||
58 | static Bool topbar = True; | ||
59 | static DC dc; | ||
60 | static Display *dpy; | ||
38 | static Item *allitems = NULL; /* first of all items */ | 61 | static Item *allitems = NULL; /* first of all items */ |
39 | static Item *item = NULL; /* first of pattern matching items */ | 62 | static Item *item = NULL; /* first of pattern matching items */ |
40 | static Item *sel = NULL; | 63 | static Item *sel = NULL; |
41 | static Item *next = NULL; | 64 | static Item *next = NULL; |
42 | static Item *prev = NULL; | 65 | static Item *prev = NULL; |
43 | static Item *curr = NULL; | 66 | static Item *curr = NULL; |
67 | static Window win, root; | ||
68 | |||
44 | static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; | 69 | static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; |
45 | static char *(*fstrstr)(const char *, const char *) = strstr; | 70 | static char *(*fstrstr)(const char *, const char *) = strstr; |
46 | static void (*calcoffsets)(void) = calcoffsetsh; | 71 | static void (*calcoffsets)(void) = calcoffsetsh; |
@@ -120,16 +145,18 @@ cleanup(void) { | |||
120 | } | 145 | } |
121 | 146 | ||
122 | void | 147 | void |
123 | dinput(void) { | 148 | drawitem(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 | ||
131 | void | 158 | void |
132 | drawbar(void) { | 159 | drawmenu(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 | ||
159 | void | 187 | void |
160 | drawitem(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 | |||
170 | void | ||
171 | drawmenuh(void) { | 188 | drawmenuh(void) { |
172 | Item *i; | 189 | Item *i; |
173 | 190 | ||
@@ -202,7 +219,19 @@ drawmenuv(void) { | |||
202 | } | 219 | } |
203 | 220 | ||
204 | void | 221 | void |
205 | kpress(XKeyEvent *e) { | 222 | grabkeyboard(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 | |||
233 | void | ||
234 | keypress(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 | ||
350 | void | 427 | void |
@@ -413,6 +490,98 @@ readstdin(void) { | |||
413 | } | 490 | } |
414 | } | 491 | } |
415 | 492 | ||
493 | void | ||
494 | run(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 | |||
515 | void | ||
516 | setup(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 | |||
416 | int | 585 | int |
417 | main(int argc, char *argv[]) { | 586 | main(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 */ | ||
12 | void drawbar(void); | ||
13 | void grabkeyboard(void); | ||
14 | void kpress(XKeyEvent *e); | ||
15 | void run(void); | ||
16 | void setup(unsigned int lines); | ||
17 | |||
18 | /* variables */ | ||
19 | extern char *prompt; | ||
20 | extern char text[4096]; | ||
21 | extern int promptw; | ||
22 | extern int screen; | ||
23 | extern unsigned int numlockmask; | ||
24 | extern unsigned int mw, mh; | ||
25 | extern unsigned long normcol[ColLast]; | ||
26 | extern unsigned long selcol[ColLast]; | ||
27 | extern Bool topbar; | ||
28 | extern DC dc; | ||
29 | extern Display *dpy; | ||
30 | extern Window win, root; | ||