aboutsummaryrefslogtreecommitdiff
path: root/dmenu.c
diff options
context:
space:
mode:
authorPhilip Wittamore <philip@wittamore.com>2025-06-08 23:39:44 +0200
committerPhilip Wittamore <philip@wittamore.com>2025-06-08 23:39:44 +0200
commitdae575e87aa42d94050ee05a290d124b20858d4e (patch)
treec19c2419f3f47cef661644b725f071f0576c50cb /dmenu.c
parent327b6e0b41e5693a059353405fb3cb8a591a1cfc (diff)
downloaddmenu-dae575e87aa42d94050ee05a290d124b20858d4e.tar.gz
dmenu-dae575e87aa42d94050ee05a290d124b20858d4e.tar.bz2
dmenu-dae575e87aa42d94050ee05a290d124b20858d4e.zip
update
Diffstat (limited to 'dmenu.c')
-rw-r--r--dmenu.c180
1 files changed, 160 insertions, 20 deletions
diff --git a/dmenu.c b/dmenu.c
index 357ba4f..67ccc27 100644
--- a/dmenu.c
+++ b/dmenu.c
@@ -26,10 +26,11 @@
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
/* enums */
-enum { SchemeNorm, SchemeSel, SchemeOut, SchemeBorder, SchemeLast }; /* color schemes */
+enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */
struct item {
char *text;
+ unsigned int width;
struct item *left, *right;
int out;
};
@@ -54,7 +55,7 @@ static Drw *drw;
static Clr *scheme[SchemeLast];
/* Temporary arrays to allow overriding xresources values */
-static char *colortemp[5];
+static char *colortemp[4];
static char *tempfonts;
#include "config.h"
@@ -105,7 +106,7 @@ max_textw(void)
{
int len = 0;
for (struct item *item = items; item && item->text; item++)
- len = MAX(TEXTW(item->text), len);
+ len = MAX(item->width, len);
return len;
}
@@ -542,6 +543,142 @@ draw:
}
static void
+buttonpress(XEvent *e)
+{
+ struct item *item;
+ XButtonPressedEvent *ev = &e->xbutton;
+ int x = 0, y = 0, h = bh, w;
+
+ if (ev->window != win)
+ return;
+
+ /* right-click: exit */
+ if (ev->button == Button3)
+ exit(1);
+
+ if (prompt && *prompt)
+ x += promptw;
+
+ /* input field */
+ w = (lines > 0 || !matches) ? mw - x : inputw;
+
+ /* 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 <= x + w +
+ ((!prev || !curr->left) ? TEXTW("<") : 0)) ||
+ (lines > 0 && ev->y >= y && ev->y <= y + h))) {
+ insert(NULL, -cursor);
+ drawmenu();
+ return;
+ }
+ /* middle-mouse click: paste selection */
+ if (ev->button == Button2) {
+ XConvertSelection(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 (ev->state & ~ControlMask)
+ return;
+ if (lines > 0) {
+ /* vertical list: (ctrl)left-click on item */
+ w = mw - x;
+ for (item = curr; item != next; item = item->right) {
+ y += h;
+ if (ev->y >= y && ev->y <= (y + h)) {
+ puts(item->text);
+ if (!(ev->state & ControlMask))
+ exit(0);
+ sel = item;
+ if (sel) {
+ sel->out = 1;
+ drawmenu();
+ }
+ return;
+ }
+ }
+ } else if (matches) {
+ /* left-click on left arrow */
+ x += inputw;
+ w = TEXTW("<");
+ if (prev && curr->left) {
+ if (ev->x >= x && ev->x <= x + w) {
+ sel = curr = prev;
+ calcoffsets();
+ drawmenu();
+ return;
+ }
+ }
+ /* horizontal list: (ctrl)left-click on item */
+ for (item = curr; item != next; item = item->right) {
+ x += w;
+ w = MIN(TEXTW(item->text), mw - x - TEXTW(">"));
+ if (ev->x >= x && ev->x <= x + w) {
+ puts(item->text);
+ if (!(ev->state & ControlMask))
+ exit(0);
+ sel = item;
+ if (sel) {
+ sel->out = 1;
+ drawmenu();
+ }
+ return;
+ }
+ }
+ /* left-click on right arrow */
+ w = TEXTW(">");
+ x = mw - w;
+ if (next && ev->x >= x && ev->x <= x + w) {
+ sel = curr = next;
+ calcoffsets();
+ drawmenu();
+ return;
+ }
+ }
+}
+
+static void
+motionevent(XButtonEvent *ev)
+{
+ struct item *it;
+ int xy, ev_xy;
+
+ if (ev->window != win || matches == 0)
+ return;
+
+ xy = lines > 0 ? bh : inputw + promptw + TEXTW("<");
+ ev_xy = lines > 0 ? ev->y : ev->x;
+ for (it = curr; it && it != next; it = it->right) {
+ int wh = lines > 0 ? bh : textw_clamp(it->text, mw - xy - TEXTW(">"));
+ if (ev_xy >= xy && ev_xy < (xy + wh)) {
+ sel = it;
+ calcoffsets();
+ drawmenu();
+ break;
+ }
+ xy += wh;
+ }
+}
+
+static void
paste(void)
{
char *p, *q;
@@ -577,6 +714,7 @@ readstdin(void)
line[len - 1] = '\0';
if (!(items[i].text = strdup(line)))
die("strdup:");
+ items[i].width = TEXTW(line);
items[i].out = 0;
}
@@ -600,6 +738,12 @@ run(void)
break;
cleanup();
exit(1);
+ case ButtonPress:
+ buttonpress(&ev);
+ break;
+ case MotionNotify:
+ motionevent(&ev.xbutton);
+ break;
case Expose:
if (ev.xexpose.count == 0)
drw_map(drw, win, 0, 0, mw, mh);
@@ -685,7 +829,7 @@ setup(void)
if (centered) {
mw = MIN(MAX(max_textw() + promptw, min_width), info[i].width);
x = info[i].x_org + ((info[i].width - mw) / 2);
- y = info[i].y_org + ((info[i].height - mh) / 2);
+ y = info[i].y_org + ((info[i].height - mh) / menu_height_ratio);
} else {
x = info[i].x_org;
y = info[i].y_org + (topbar ? 0 : info[i].height - mh);
@@ -708,21 +852,23 @@ setup(void)
x = 0;
y = topbar ? 0 : wa.height - mh;
mw = wa.width;
- }
+ }
}
-
+ promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
inputw = mw / 3; /* input width: ~33% of monitor width */
match();
/* create menu window */
swa.override_redirect = True;
swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
- swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
+ swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask |
+ ButtonPressMask | PointerMotionMask;
win = XCreateWindow(dpy, parentwin, x, y - (topbar ? 0 : border_width * 2), mw - border_width * 2, mh, border_width,
- CopyFromParent, CopyFromParent, CopyFromParent,
- CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
+ CopyFromParent, CopyFromParent, CopyFromParent,
+ CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
if (border_width)
- XSetWindowBorder(dpy, win, scheme[SchemeBorder][ColFg].pixel);
+ XSetWindowBorder(dpy, win, scheme[SchemeSel][ColBg].pixel);
+
XSetClassHint(dpy, win, &ch);
/* input methods */
@@ -784,10 +930,6 @@ readxresources(void) {
colors[SchemeSel][ColFg] = strdup(xval.addr);
else
colors[SchemeSel][ColFg] = strdup(colors[SchemeSel][ColFg]);
- if (XrmGetResource(xdb, "dmenu.border", "*", &type, &xval))
- colors[SchemeBorder][ColFg] = strdup(xval.addr);
- else
- colors[SchemeBorder][ColFg] = strdup(colors[SchemeBorder][ColFg]);
XrmDestroyDatabase(xdb);
}
@@ -856,15 +998,13 @@ main(int argc, char *argv[])
if ( tempfonts )
fonts[0] = strdup(tempfonts);
if ( colortemp[0])
- colors[SchemeNorm][ColBg] = strdup(colortemp[0]);
+ colors[SchemeNorm][ColBg] = strdup(colortemp[0]);
if ( colortemp[1])
- colors[SchemeNorm][ColFg] = strdup(colortemp[1]);
+ colors[SchemeNorm][ColFg] = strdup(colortemp[1]);
if ( colortemp[2])
- colors[SchemeSel][ColBg] = strdup(colortemp[2]);
+ colors[SchemeSel][ColBg] = strdup(colortemp[2]);
if ( colortemp[3])
- colors[SchemeSel][ColFg] = strdup(colortemp[3]);
- if ( colortemp[4])
- colors[SchemeBorder][ColFg] = strdup(colortemp[4]);
+ colors[SchemeSel][ColFg] = strdup(colortemp[3]);
if (!drw_fontset_create(drw, (const char**)fonts, LENGTH(fonts)))
die("no fonts could be loaded.");