diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | config.mk | 2 | ||||
-rw-r--r-- | dmenu.1 | 3 | ||||
-rw-r--r-- | dmenu.h | 7 | ||||
-rw-r--r-- | draw.c | 121 | ||||
-rw-r--r-- | main.c | 127 |
6 files changed, 130 insertions, 132 deletions
@@ -3,7 +3,7 @@ | |||
3 | 3 | ||
4 | include config.mk | 4 | include config.mk |
5 | 5 | ||
6 | SRC = draw.c main.c util.c | 6 | SRC = main.c util.c |
7 | OBJ = ${SRC:.c=.o} | 7 | OBJ = ${SRC:.c=.o} |
8 | 8 | ||
9 | all: options dmenu | 9 | all: options dmenu |
@@ -1,5 +1,5 @@ | |||
1 | # dmenu version | 1 | # dmenu version |
2 | VERSION = 2.2 | 2 | VERSION = 2.3 |
3 | 3 | ||
4 | # Customize below to fit your system | 4 | # Customize below to fit your system |
5 | 5 | ||
@@ -90,6 +90,9 @@ Remove enough characters from the input field to change its filtering effect. | |||
90 | .TP | 90 | .TP |
91 | .B Control-u | 91 | .B Control-u |
92 | Remove all characters from the input field. | 92 | Remove all characters from the input field. |
93 | .TP | ||
94 | .B Control-w | ||
95 | Remove all characters of current word from the input field. | ||
93 | .SH SEE ALSO | 96 | .SH SEE ALSO |
94 | .BR dwm (1), | 97 | .BR dwm (1), |
95 | .BR wmii (1) . | 98 | .BR wmii (1) . |
@@ -38,13 +38,6 @@ extern int screen; | |||
38 | extern Display *dpy; | 38 | extern Display *dpy; |
39 | extern DC dc; /* global drawing context */ | 39 | extern DC dc; /* global drawing context */ |
40 | 40 | ||
41 | /* draw.c */ | ||
42 | extern void drawtext(const char *text, | ||
43 | unsigned long col[ColLast]); /* draws text with the defined color tuple */ | ||
44 | extern unsigned long getcolor(const char *colstr); /* returns color of colstr */ | ||
45 | extern void setfont(const char *fontstr); /* sets global font */ | ||
46 | extern unsigned int textw(const char *text); /* returns width of text in px */ | ||
47 | |||
48 | /* util.c */ | 41 | /* util.c */ |
49 | extern void *emalloc(unsigned int size); /* allocates memory, exits on error */ | 42 | extern void *emalloc(unsigned int size); /* allocates memory, exits on error */ |
50 | extern void eprint(const char *errstr, ...); /* prints errstr and exits with 1 */ | 43 | extern void eprint(const char *errstr, ...); /* prints errstr and exits with 1 */ |
@@ -1,121 +0,0 @@ | |||
1 | /* (C)opyright MMIV-MMVII Anselm R. Garbe <garbeam at gmail dot com> | ||
2 | * See LICENSE file for license details. | ||
3 | */ | ||
4 | #include "dmenu.h" | ||
5 | #include <stdio.h> | ||
6 | #include <string.h> | ||
7 | |||
8 | /* static */ | ||
9 | |||
10 | static unsigned int | ||
11 | textnw(const char *text, unsigned int len) { | ||
12 | XRectangle r; | ||
13 | |||
14 | if(dc.font.set) { | ||
15 | XmbTextExtents(dc.font.set, text, len, NULL, &r); | ||
16 | return r.width; | ||
17 | } | ||
18 | return XTextWidth(dc.font.xfont, text, len); | ||
19 | } | ||
20 | |||
21 | /* extern */ | ||
22 | |||
23 | void | ||
24 | drawtext(const char *text, unsigned long col[ColLast]) { | ||
25 | int x, y, w, h; | ||
26 | static char buf[256]; | ||
27 | unsigned int len, olen; | ||
28 | XGCValues gcv; | ||
29 | XRectangle r = { dc.x, dc.y, dc.w, dc.h }; | ||
30 | |||
31 | XSetForeground(dpy, dc.gc, col[ColBG]); | ||
32 | XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); | ||
33 | if(!text) | ||
34 | return; | ||
35 | w = 0; | ||
36 | olen = len = strlen(text); | ||
37 | if(len >= sizeof buf) | ||
38 | len = sizeof buf - 1; | ||
39 | memcpy(buf, text, len); | ||
40 | buf[len] = 0; | ||
41 | h = dc.font.ascent + dc.font.descent; | ||
42 | y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; | ||
43 | x = dc.x + (h / 2); | ||
44 | /* shorten text if necessary */ | ||
45 | while(len && (w = textnw(buf, len)) > dc.w - h) | ||
46 | buf[--len] = 0; | ||
47 | if(len < olen) { | ||
48 | if(len > 1) | ||
49 | buf[len - 1] = '.'; | ||
50 | if(len > 2) | ||
51 | buf[len - 2] = '.'; | ||
52 | if(len > 3) | ||
53 | buf[len - 3] = '.'; | ||
54 | } | ||
55 | if(w > dc.w) | ||
56 | return; /* too long */ | ||
57 | gcv.foreground = col[ColFG]; | ||
58 | if(dc.font.set) { | ||
59 | XChangeGC(dpy, dc.gc, GCForeground, &gcv); | ||
60 | XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, | ||
61 | x, y, buf, len); | ||
62 | } | ||
63 | else { | ||
64 | gcv.font = dc.font.xfont->fid; | ||
65 | XChangeGC(dpy, dc.gc, GCForeground | GCFont, &gcv); | ||
66 | XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | unsigned long | ||
71 | getcolor(const char *colstr) { | ||
72 | Colormap cmap = DefaultColormap(dpy, screen); | ||
73 | XColor color; | ||
74 | |||
75 | if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) | ||
76 | eprint("error, cannot allocate color '%s'\n", colstr); | ||
77 | return color.pixel; | ||
78 | } | ||
79 | |||
80 | void | ||
81 | setfont(const char *fontstr) { | ||
82 | char *def, **missing; | ||
83 | int i, n; | ||
84 | |||
85 | missing = NULL; | ||
86 | if(dc.font.set) | ||
87 | XFreeFontSet(dpy, dc.font.set); | ||
88 | dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); | ||
89 | if(missing) | ||
90 | XFreeStringList(missing); | ||
91 | if(dc.font.set) { | ||
92 | XFontSetExtents *font_extents; | ||
93 | XFontStruct **xfonts; | ||
94 | char **font_names; | ||
95 | dc.font.ascent = dc.font.descent = 0; | ||
96 | font_extents = XExtentsOfFontSet(dc.font.set); | ||
97 | n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); | ||
98 | for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) { | ||
99 | if(dc.font.ascent < (*xfonts)->ascent) | ||
100 | dc.font.ascent = (*xfonts)->ascent; | ||
101 | if(dc.font.descent < (*xfonts)->descent) | ||
102 | dc.font.descent = (*xfonts)->descent; | ||
103 | xfonts++; | ||
104 | } | ||
105 | } | ||
106 | else { | ||
107 | if(dc.font.xfont) | ||
108 | XFreeFont(dpy, dc.font.xfont); | ||
109 | dc.font.xfont = NULL; | ||
110 | if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))) | ||
111 | eprint("error, cannot load font: '%s'\n", fontstr); | ||
112 | dc.font.ascent = dc.font.xfont->ascent; | ||
113 | dc.font.descent = dc.font.xfont->descent; | ||
114 | } | ||
115 | dc.font.height = dc.font.ascent + dc.font.descent; | ||
116 | } | ||
117 | |||
118 | unsigned int | ||
119 | textw(const char *text) { | ||
120 | return textnw(text, strlen(text)) + dc.font.height; | ||
121 | } | ||
@@ -44,6 +44,22 @@ static Item *curr = NULL; | |||
44 | static Window root; | 44 | static Window root; |
45 | static Window win; | 45 | static Window win; |
46 | 46 | ||
47 | static unsigned int | ||
48 | textnw(const char *text, unsigned int len) { | ||
49 | XRectangle r; | ||
50 | |||
51 | if(dc.font.set) { | ||
52 | XmbTextExtents(dc.font.set, text, len, NULL, &r); | ||
53 | return r.width; | ||
54 | } | ||
55 | return XTextWidth(dc.font.xfont, text, len); | ||
56 | } | ||
57 | |||
58 | static unsigned int | ||
59 | textw(const char *text) { | ||
60 | return textnw(text, strlen(text)) + dc.font.height; | ||
61 | } | ||
62 | |||
47 | static void | 63 | static void |
48 | calcoffsets(void) { | 64 | calcoffsets(void) { |
49 | unsigned int tw, w; | 65 | unsigned int tw, w; |
@@ -71,6 +87,53 @@ calcoffsets(void) { | |||
71 | } | 87 | } |
72 | 88 | ||
73 | static void | 89 | static void |
90 | drawtext(const char *text, unsigned long col[ColLast]) { | ||
91 | int x, y, w, h; | ||
92 | static char buf[256]; | ||
93 | unsigned int len, olen; | ||
94 | XGCValues gcv; | ||
95 | XRectangle r = { dc.x, dc.y, dc.w, dc.h }; | ||
96 | |||
97 | XSetForeground(dpy, dc.gc, col[ColBG]); | ||
98 | XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); | ||
99 | if(!text) | ||
100 | return; | ||
101 | w = 0; | ||
102 | olen = len = strlen(text); | ||
103 | if(len >= sizeof buf) | ||
104 | len = sizeof buf - 1; | ||
105 | memcpy(buf, text, len); | ||
106 | buf[len] = 0; | ||
107 | h = dc.font.ascent + dc.font.descent; | ||
108 | y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; | ||
109 | x = dc.x + (h / 2); | ||
110 | /* shorten text if necessary */ | ||
111 | while(len && (w = textnw(buf, len)) > dc.w - h) | ||
112 | buf[--len] = 0; | ||
113 | if(len < olen) { | ||
114 | if(len > 1) | ||
115 | buf[len - 1] = '.'; | ||
116 | if(len > 2) | ||
117 | buf[len - 2] = '.'; | ||
118 | if(len > 3) | ||
119 | buf[len - 3] = '.'; | ||
120 | } | ||
121 | if(w > dc.w) | ||
122 | return; /* too long */ | ||
123 | gcv.foreground = col[ColFG]; | ||
124 | if(dc.font.set) { | ||
125 | XChangeGC(dpy, dc.gc, GCForeground, &gcv); | ||
126 | XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, | ||
127 | x, y, buf, len); | ||
128 | } | ||
129 | else { | ||
130 | gcv.font = dc.font.xfont->fid; | ||
131 | XChangeGC(dpy, dc.gc, GCForeground | GCFont, &gcv); | ||
132 | XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | static void | ||
74 | drawmenu(void) { | 137 | drawmenu(void) { |
75 | Item *i; | 138 | Item *i; |
76 | 139 | ||
@@ -111,6 +174,54 @@ drawmenu(void) { | |||
111 | XFlush(dpy); | 174 | XFlush(dpy); |
112 | } | 175 | } |
113 | 176 | ||
177 | static unsigned long | ||
178 | getcolor(const char *colstr) { | ||
179 | Colormap cmap = DefaultColormap(dpy, screen); | ||
180 | XColor color; | ||
181 | |||
182 | if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) | ||
183 | eprint("error, cannot allocate color '%s'\n", colstr); | ||
184 | return color.pixel; | ||
185 | } | ||
186 | |||
187 | static void | ||
188 | setfont(const char *fontstr) { | ||
189 | char *def, **missing; | ||
190 | int i, n; | ||
191 | |||
192 | missing = NULL; | ||
193 | if(dc.font.set) | ||
194 | XFreeFontSet(dpy, dc.font.set); | ||
195 | dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); | ||
196 | if(missing) | ||
197 | XFreeStringList(missing); | ||
198 | if(dc.font.set) { | ||
199 | XFontSetExtents *font_extents; | ||
200 | XFontStruct **xfonts; | ||
201 | char **font_names; | ||
202 | dc.font.ascent = dc.font.descent = 0; | ||
203 | font_extents = XExtentsOfFontSet(dc.font.set); | ||
204 | n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); | ||
205 | for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) { | ||
206 | if(dc.font.ascent < (*xfonts)->ascent) | ||
207 | dc.font.ascent = (*xfonts)->ascent; | ||
208 | if(dc.font.descent < (*xfonts)->descent) | ||
209 | dc.font.descent = (*xfonts)->descent; | ||
210 | xfonts++; | ||
211 | } | ||
212 | } | ||
213 | else { | ||
214 | if(dc.font.xfont) | ||
215 | XFreeFont(dpy, dc.font.xfont); | ||
216 | dc.font.xfont = NULL; | ||
217 | if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))) | ||
218 | eprint("error, cannot load font: '%s'\n", fontstr); | ||
219 | dc.font.ascent = dc.font.xfont->ascent; | ||
220 | dc.font.descent = dc.font.xfont->descent; | ||
221 | } | ||
222 | dc.font.height = dc.font.ascent + dc.font.descent; | ||
223 | } | ||
224 | |||
114 | static void | 225 | static void |
115 | match(char *pattern) { | 226 | match(char *pattern) { |
116 | unsigned int plen; | 227 | unsigned int plen; |
@@ -151,8 +262,8 @@ match(char *pattern) { | |||
151 | static void | 262 | static void |
152 | kpress(XKeyEvent * e) { | 263 | kpress(XKeyEvent * e) { |
153 | char buf[32]; | 264 | char buf[32]; |
154 | int num, prev_nitem; | 265 | int i, num, prev_nitem; |
155 | unsigned int i, len; | 266 | unsigned int len; |
156 | KeySym ksym; | 267 | KeySym ksym; |
157 | 268 | ||
158 | len = strlen(text); | 269 | len = strlen(text); |
@@ -188,6 +299,18 @@ kpress(XKeyEvent * e) { | |||
188 | match(text); | 299 | match(text); |
189 | drawmenu(); | 300 | drawmenu(); |
190 | return; | 301 | return; |
302 | case XK_w: | ||
303 | case XK_W: | ||
304 | if(len) { | ||
305 | i = len - 1; | ||
306 | while(i >= 0 && text[i] == ' ') | ||
307 | text[i--] = 0; | ||
308 | while(i >= 0 && text[i] != ' ') | ||
309 | text[i--] = 0; | ||
310 | match(text); | ||
311 | drawmenu(); | ||
312 | } | ||
313 | return; | ||
191 | } | 314 | } |
192 | } | 315 | } |
193 | if(CLEANMASK(e->state) & Mod1Mask) { | 316 | if(CLEANMASK(e->state) & Mod1Mask) { |