summaryrefslogtreecommitdiff
path: root/ui.c
diff options
context:
space:
mode:
Diffstat (limited to 'ui.c')
-rw-r--r--ui.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/ui.c b/ui.c
new file mode 100644
index 0000000..542cb8b
--- /dev/null
+++ b/ui.c
@@ -0,0 +1,149 @@
+/* xmenu
+ * a simple fuzzy-selection menu made with Xlib
+ */
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/XKBlib.h>
+#include <stdio.h>
+
+#include "dynarr.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;
+}