diff --git a/dmenu.c b/dmenu.c index 3962801..a75bf80 100644 --- a/dmenu.c +++ b/dmenu.c @@ -25,6 +25,7 @@ struct Item { }; static void appenditem(Item *item, Item **list, Item **last); +static void buttonpress(XEvent *e); static void calcoffsets(void); static char *cistrstr(const char *s, const char *sub); static void drawmenu(void); @@ -389,6 +390,109 @@ keypress(XKeyEvent *ev) { } void +buttonpress(XEvent *e) { + int curpos; + Item *item; + XButtonPressedEvent *ev = &e->xbutton; + + if(ev->window != win) + return; + + /* right-click: exit */ + if(ev->button == Button3) + exit(EXIT_FAILURE); + + dc->x = 0; + dc->y = 0; + dc->h = bh; + + if(prompt && *prompt) { + dc->w = promptw; + dc->x = dc->w; + } + /* input field */ + dc->w = (lines > 0 || !matches) ? mw - dc->x : inputw; + if((curpos = textnw(dc, text, cursor) + dc->h/2 - 2) < dc->w); + + /* left-click on input: clear input, + * NOTE: if there is no left-arrow the space for < is reserved so + * add that to the input width */ + if(ev->button == Button1 && + ((lines <= 0 && ev->x >= 0 && ev->x <= dc->x + dc->w + + ((!prev || !curr->left) ? textw(dc, "<") : 0)) || + (lines > 0 && ev->y >= dc->y && ev->y <= dc->y + dc->h))) { + insert(NULL, 0 - cursor); + drawmenu(); + return; + } + /* middle-mouse click: paste selection */ + if(ev->button == Button2) { + XConvertSelection(dc->dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY, + utf8, utf8, win, CurrentTime); + drawmenu(); + return; + } + /* scroll up */ + if(ev->button == Button4 && prev) { + sel = curr = prev; + calcoffsets(); + drawmenu(); + return; + } + /* scroll down */ + if(ev->button == Button5 && next) { + sel = curr = next; + calcoffsets(); + drawmenu(); + return; + } + if(ev->button != Button1) + return; + if(lines > 0) { + /* vertical list: left-click on item */ + dc->w = mw - dc->x; + for(item = curr; item != next; item = item->right) { + dc->y += dc->h; + if(ev->y >= dc->y && ev->y <= (dc->y + dc->h)) { + puts(item->text); + exit(EXIT_SUCCESS); + } + } + } + else if(matches) { + /* left-click on left arrow */ + dc->x += inputw; + dc->w = textw(dc, "<"); + if(prev && curr->left) { + if(ev->x >= dc->x && ev->x <= dc->x + dc->w) { + sel = curr = prev; + calcoffsets(); + drawmenu(); + return; + } + } + /* horizontal list: left-click on item */ + for(item = curr; item != next; item = item->right) { + dc->x += dc->w; + dc->w = MIN(textw(dc, item->text), mw - dc->x - textw(dc, ">")); + if(ev->x >= dc->x && ev->x <= (dc->x + dc->w)) { + puts(item->text); + exit(EXIT_SUCCESS); + } + } + /* left-click on right arrow */ + dc->w = textw(dc, ">"); + dc->x = mw - dc->w; + if(next && ev->x >= dc->x && ev->x <= dc->x + dc->w) { + sel = curr = next; + calcoffsets(); + drawmenu(); + return; + } + } +} + +void match(void) { static char **tokv = NULL; static int tokn = 0; @@ -497,6 +601,9 @@ run(void) { if(XFilterEvent(&ev, win)) continue; switch(ev.type) { + case ButtonPress: + buttonpress(&ev); + break; case Expose: if(ev.xexpose.count == 0) mapdc(dc, win, mw, mh); @@ -586,7 +693,8 @@ setup(void) { /* create menu window */ swa.override_redirect = True; swa.background_pixel = normcol[ColBG]; - swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; + swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask | + ButtonPressMask; win = XCreateWindow(dc->dpy, root, x, y, mw, mh, 0, DefaultDepth(dc->dpy, screen), CopyFromParent, DefaultVisual(dc->dpy, screen),