aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dmenu.c72
1 files changed, 35 insertions, 37 deletions
diff --git a/dmenu.c b/dmenu.c
index f16249c..9b6a382 100644
--- a/dmenu.c
+++ b/dmenu.c
@@ -15,7 +15,6 @@
15#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))
16#define MIN(a,b) ((a) < (b) ? (a) : (b)) 16#define MIN(a,b) ((a) < (b) ? (a) : (b))
17#define MAX(a,b) ((a) > (b) ? (a) : (b)) 17#define MAX(a,b) ((a) > (b) ? (a) : (b))
18#define UTF8_CODEPOINT(c) (((c) & 0xc0) != 0x80)
19 18
20typedef struct Item Item; 19typedef struct Item Item;
21struct Item { 20struct Item {
@@ -32,7 +31,8 @@ static void grabkeyboard(void);
32static void insert(const char *s, ssize_t n); 31static void insert(const char *s, ssize_t n);
33static void keypress(XKeyEvent *ev); 32static void keypress(XKeyEvent *ev);
34static void match(void); 33static void match(void);
35static void paste(Atom atom); 34static size_t nextrune(int incr);
35static void paste(void);
36static void readstdin(void); 36static void readstdin(void);
37static void run(void); 37static void run(void);
38static void setup(void); 38static void setup(void);
@@ -52,7 +52,7 @@ static unsigned int lines = 0;
52static unsigned int promptw; 52static unsigned int promptw;
53static unsigned long normcol[ColLast]; 53static unsigned long normcol[ColLast];
54static unsigned long selcol[ColLast]; 54static unsigned long selcol[ColLast];
55static Atom clip, utf8; 55static Atom utf8;
56static Bool topbar = True; 56static Bool topbar = True;
57static DC *dc; 57static DC *dc;
58static Item *items = NULL; 58static Item *items = NULL;
@@ -159,7 +159,9 @@ grabkeyboard(void) {
159 159
160void 160void
161insert(const char *s, ssize_t n) { 161insert(const char *s, ssize_t n) {
162 memmove(text + cursor + n, text + cursor, sizeof text - cursor - n); 162 if(strlen(text) + n > sizeof text - 1)
163 return;
164 memmove(text + cursor + n, text + cursor, sizeof text - cursor - MAX(n, 0));
163 if(n > 0) 165 if(n > 0)
164 memcpy(text + cursor, s, n); 166 memcpy(text + cursor, s, n);
165 cursor += n; 167 cursor += n;
@@ -169,7 +171,6 @@ insert(const char *s, ssize_t n) {
169void 171void
170keypress(XKeyEvent *ev) { 172keypress(XKeyEvent *ev) {
171 char buf[32]; 173 char buf[32];
172 int n;
173 size_t len; 174 size_t len;
174 KeySym ksym; 175 KeySym ksym;
175 176
@@ -217,38 +218,31 @@ keypress(XKeyEvent *ev) {
217 ksym = XK_Up; 218 ksym = XK_Up;
218 break; 219 break;
219 case XK_u: /* delete left */ 220 case XK_u: /* delete left */
220 insert(NULL, -cursor); 221 insert(NULL, 0 - cursor);
221 break; 222 break;
222 case XK_w: /* delete word */ 223 case XK_w: /* delete word */
223 if(cursor == 0) 224 while(cursor > 0 && text[nextrune(-1)] == ' ')
224 return; 225 insert(NULL, nextrune(-1) - cursor);
225 n = 0; 226 while(cursor > 0 && text[nextrune(-1)] != ' ')
226 while(cursor - n++ > 0 && text[cursor - n] == ' '); 227 insert(NULL, nextrune(-1) - cursor);
227 while(cursor - n++ > 0 && text[cursor - n] != ' ');
228 insert(NULL, 1-n);
229 break; 228 break;
230 case XK_y: /* paste selection */ 229 case XK_y: /* paste selection */
231 XConvertSelection(dc->dpy, XA_PRIMARY, utf8, clip, win, CurrentTime); 230 XConvertSelection(dc->dpy, XA_PRIMARY, utf8, utf8, win, CurrentTime);
232 return; 231 return;
233 } 232 }
234 } 233 }
235 switch(ksym) { 234 switch(ksym) {
236 default: 235 default:
237 if(isprint(*buf)) 236 if(isprint(*buf))
238 insert(buf, MIN(strlen(buf), sizeof text - cursor)); 237 insert(buf, strlen(buf));
239 break;
240 case XK_BackSpace:
241 if(cursor == 0)
242 return;
243 for(n = 1; cursor - n > 0 && !UTF8_CODEPOINT(text[cursor - n]); n++);
244 insert(NULL, -n);
245 break; 238 break;
246 case XK_Delete: 239 case XK_Delete:
247 if(cursor == len) 240 if(cursor == len)
248 return; 241 return;
249 for(n = 1; cursor + n < len && !UTF8_CODEPOINT(text[cursor + n]); n++); 242 cursor = nextrune(+1);
250 cursor += n; 243 case XK_BackSpace:
251 insert(NULL, -n); 244 if(cursor > 0)
245 insert(NULL, nextrune(-1) - cursor);
252 break; 246 break;
253 case XK_End: 247 case XK_End:
254 if(cursor < len) { 248 if(cursor < len) {
@@ -274,15 +268,13 @@ keypress(XKeyEvent *ev) {
274 break; 268 break;
275 case XK_Left: 269 case XK_Left:
276 if(cursor > 0 && (!sel || !sel->left || lines > 0)) { 270 if(cursor > 0 && (!sel || !sel->left || lines > 0)) {
277 while(cursor-- > 0 && !UTF8_CODEPOINT(text[cursor])); 271 cursor = nextrune(-1);
278 break; 272 break;
279 } 273 }
280 else if(lines > 0) 274 else if(lines > 0)
281 return; 275 return;
282 case XK_Up: 276 case XK_Up:
283 if(!sel || !sel->left) 277 if(sel && sel->left && (sel = sel->left)->right == curr) {
284 return;
285 if((sel = sel->left)->right == curr) {
286 curr = prev; 278 curr = prev;
287 calcoffsets(); 279 calcoffsets();
288 } 280 }
@@ -306,15 +298,13 @@ keypress(XKeyEvent *ev) {
306 exit(EXIT_SUCCESS); 298 exit(EXIT_SUCCESS);
307 case XK_Right: 299 case XK_Right:
308 if(cursor < len) { 300 if(cursor < len) {
309 while(cursor++ < len && !UTF8_CODEPOINT(text[cursor])); 301 cursor = nextrune(+1);
310 break; 302 break;
311 } 303 }
312 else if(lines > 0) 304 else if(lines > 0)
313 return; 305 return;
314 case XK_Down: 306 case XK_Down:
315 if(!sel || !sel->right) 307 if(sel && sel->right && (sel = sel->right) == next) {
316 return;
317 if((sel = sel->right) == next) {
318 curr = next; 308 curr = next;
319 calcoffsets(); 309 calcoffsets();
320 } 310 }
@@ -370,14 +360,23 @@ match(void) {
370 calcoffsets(); 360 calcoffsets();
371} 361}
372 362
363size_t
364nextrune(int incr) {
365 size_t n, len;
366
367 len = strlen(text);
368 for(n = cursor + incr; n >= 0 && n < len && (text[n] & 0xc0) == 0x80; n += incr);
369 return n;
370}
371
373void 372void
374paste(Atom atom) { 373paste(void) {
375 char *p, *q; 374 char *p, *q;
376 int di; 375 int di;
377 unsigned long dl; 376 unsigned long dl;
378 Atom da; 377 Atom da;
379 378
380 XGetWindowProperty(dc->dpy, win, atom, 0, sizeof text - cursor, False, 379 XGetWindowProperty(dc->dpy, win, utf8, 0, (sizeof text / 4) + 1, False,
381 utf8, &da, &di, &dl, &dl, (unsigned char **)&p); 380 utf8, &da, &di, &dl, &dl, (unsigned char **)&p);
382 insert(p, (q = strchr(p, '\n')) ? q-p : strlen(p)); 381 insert(p, (q = strchr(p, '\n')) ? q-p : strlen(p));
383 XFree(p); 382 XFree(p);
@@ -396,8 +395,8 @@ readstdin(void) {
396 eprintf("cannot malloc %u bytes\n", sizeof *item); 395 eprintf("cannot malloc %u bytes\n", sizeof *item);
397 if(!(item->text = strdup(buf))) 396 if(!(item->text = strdup(buf)))
398 eprintf("cannot strdup %u bytes\n", strlen(buf)+1); 397 eprintf("cannot strdup %u bytes\n", strlen(buf)+1);
399 inputw = MAX(inputw, textw(dc, item->text));
400 item->next = item->left = item->right = NULL; 398 item->next = item->left = item->right = NULL;
399 inputw = MAX(inputw, textw(dc, item->text));
401 } 400 }
402} 401}
403 402
@@ -415,8 +414,8 @@ run(void) {
415 keypress(&ev.xkey); 414 keypress(&ev.xkey);
416 break; 415 break;
417 case SelectionNotify: 416 case SelectionNotify:
418 if(ev.xselection.property != None) 417 if(ev.xselection.property == utf8)
419 paste(ev.xselection.property); 418 paste();
420 break; 419 break;
421 case VisibilityNotify: 420 case VisibilityNotify:
422 if(ev.xvisibility.state != VisibilityUnobscured) 421 if(ev.xvisibility.state != VisibilityUnobscured)
@@ -437,7 +436,6 @@ setup(void) {
437 screen = DefaultScreen(dc->dpy); 436 screen = DefaultScreen(dc->dpy);
438 root = RootWindow(dc->dpy, screen); 437 root = RootWindow(dc->dpy, screen);
439 utf8 = XInternAtom(dc->dpy, "UTF8_STRING", False); 438 utf8 = XInternAtom(dc->dpy, "UTF8_STRING", False);
440 clip = XInternAtom(dc->dpy, "_DMENU_STRING", False);
441 439
442 normcol[ColBG] = getcolor(dc, normbgcolor); 440 normcol[ColBG] = getcolor(dc, normbgcolor);
443 normcol[ColFG] = getcolor(dc, normfgcolor); 441 normcol[ColFG] = getcolor(dc, normfgcolor);