/* xmenu * a simple fuzzy-selection menu made with Xlib */ #include #include #include #include #define ARENA_IMPL #define STR_IMPL #include "arena.h" #include "dynarr.h" #include "str.h" typedef DYNARR(char) DynStr; int umod(int a, int b) { if (a < 0) { return b + a % b; } else { return a % b; } } int main(int argc, char **argv) { Display *dsp = XOpenDisplay(""); int scr = DefaultScreen(dsp); unsigned long fg = BlackPixel(dsp, scr); unsigned long bg = WhitePixel(dsp, scr); XSizeHints szhint = { 0 }; szhint.width = 350; szhint.height = 250; szhint.flags = PSize; Window win = XCreateSimpleWindow( dsp, DefaultRootWindow(dsp), szhint.x, szhint.y, szhint.width, szhint.height, 5 /* border width */, fg, bg); char title[] = "xmenu"; XSetStandardProperties(dsp, win, title, title, None, argv, argc, &szhint); GC gc = XCreateGC(dsp, win, 0, 0); XSetBackground(dsp, gc, bg); XSetForeground(dsp, gc, fg); XSelectInput(dsp, win, ButtonPressMask | KeyPressMask | ExposureMask); XMapRaised(dsp, win); Font freg = XLoadFont(dsp, "-*-new century schoolbook-medium-r-*-*-24-*-*-*-*-*-*-*"); Font fital = XLoadFont(dsp, "-*-new century schoolbook-medium-i-*-*-24-*-*-*-*-*-*-*"); /* see Xft(3) */ DynStr input = { 0 }; int seli = 0; const char *optv[] = { "she shit on my thang until i vomit", "what", "who are you", "why are you", "where'd you come from" }; int optc = sizeof optv / sizeof *optv; for (;;) { XEvent ev; KeySym key; XNextEvent(dsp, &ev); switch (ev.type) { case KeyPress: { char kbuf[32]; KeyCode kc = ev.xkey.keycode; KeySym sym = XkbKeycodeToKeysym(dsp, kc, 0, !!(ev.xkey.state & ShiftMask)); int rune = ksym_to_unicode(sym); switch (sym) { case XK_Escape: goto done; case XK_BackSpace: if (input.n > 0) input.n--; goto draw; case XK_Return: input.n = 0; goto draw; case XK_Down: seli = umod(seli + 1, optc); goto draw; case XK_Up: seli = umod(seli - 1, optc); goto draw; default: { int n = XLookupString(&ev.xkey, kbuf, 10, &key, 0); if (!n) break; DA_PUSH_MULT(&input, kbuf, n); seli = 0; goto draw; } break; } } break; case Expose: { draw:; XWindowAttributes attr; XClearWindow(dsp, win); XGetWindowAttributes(dsp, win, &attr); //XGetSizeHints(dsp, win, &szhint); XSetFont(dsp, gc, fital); int w = XTextWidth(XQueryFont(dsp, XGContextFromGC(gc)), input.v, input.n); DA_PUSH(&input, '_'); XDrawString(dsp, win, gc, 16, 24, input.v, input.n); input.n--; XSetFont(dsp, gc, freg); for (int i = 0; i < optc; i++) { if (i == seli) { int w = XTextWidth(XQueryFont(dsp, XGContextFromGC(gc)), optv[i], strlen(optv[i])); XFillRectangle(dsp, win, gc, 16, 28 + i * 24 + 8, w, 24); XSetForeground(dsp, gc, bg); XDrawString(dsp, win, gc, 16, 48 + i * 24 + 8, optv[i], strlen(optv[i])); XSetForeground(dsp, gc, fg); } else { XDrawString(dsp, win, gc, 16, 48 + i * 24 + 8, optv[i], strlen(optv[i])); } } } break; /* TODO: figure out quit events */ } } done: ; XUnloadFont(dsp, freg); XUnloadFont(dsp, fital); XFreeGC(dsp, gc); XDestroyWindow(dsp, win); XCloseDisplay(dsp); return 0; }