commit - 00b627fd46410a018b320c3922c3e5912b68c438
commit + 843ffc790805c026d5aad57ff70c2aa4c8d1a559
blob - 17c35503c95c34e4208af16ebf84c29e390cae6e
blob + cedd4aa10eb18ca8cbfdde4f37854e84f927556a
--- xitems.c
+++ xitems.c
#include <X11/Xatom.h>
#define PROGNAME "xitems"
+#define MAXKS 32
#define LEN(A) (sizeof(A)/sizeof((A)[0]))
exit(eval);
}
+/* warn -- print formatted string to stderr. */
+static void
+warn(const char *fmt, ...)
+{
+ fputs(PROGNAME ": ", stderr);
+ if (fmt) {
+ va_list argp;
+ va_start(argp, fmt);
+ vfprintf(stderr, fmt, argp);
+ va_end(argp);
+ }
+ fputc('\n', stderr);
+}
+
enum direction {
DIR_UP,
DIR_DOWN
/* doubly-linked cyclic list */
struct item {
- size_t len; /* length of string */
- char *s;
- KeySym *ks; /* NoSym-terminated array of keysyms */
struct item *prev;
struct item *next;
+ char *s;
+ KeySym ks[MAXKS]; /* array of associated keysyms */
+ size_t len; /* length of string */
+ size_t nks; /* number of associated keysyms */
bool dirty; /* should be redrawn */
};
static XFontStruct *font;
static int height, width; /* height and width of one item */
-/* newsel -- mark the item at position y (from top) as selected. */
+/* selpos -- mark the item at position y (from top) as selected. */
static void
-newsel(int y)
+selpos(int y)
{
struct item *unselected = selected;
int top = 1;
if (y <= 0)
goto end;
- do {
+ for (selected = first; selected != first->prev;
+ selected = selected->next) {
if (y >= top && y < top+height)
break;
top += height;
- selected = selected->next;
- } while (selected != first->prev);
+ }
end:
if (unselected != selected)
} else
selected = (dir == DIR_UP) ? first->prev : first;
selected->dirty = true;
+}
+
+/*
+ * keyselectd -- compare ks with keysyms stored in the items list, and mark
+ * the first match as selected. Return true on match, and false otherwise.
+ */
+static bool
+keyselect(KeySym ks)
+{
+ struct item *it = first;
+ KeySym k, dummy;
+
+ XConvertCase(ks, &k, &dummy);
+
+ do {
+ size_t i;
+ for (i = 0; i < it->nks; ++i)
+ if (it->ks[i] == k) {
+ selected->dirty = true;
+ selected = it;
+ selected->dirty = true;
+ return true;
+ }
+ it = it->next;
+ } while (it != first);
+
+ return false;
}
/* proc -- body of the main event-reading loop. */
inwin = true;
/* FALLTHRU */
case MotionNotify:
- newsel(ev.xbutton.y);
+ selpos(ev.xbutton.y);
/* FALLTHRU */
case Expose:
redraw();
ks = XK_k;
return;
}
- }
+ } else if (keyselect(ks))
+ succeed(true);
switch (ks) {
case XK_j:
* to the new item. Return NULL otherwise.
*/
static struct item *
-insitem(struct item *it, char *s, size_t len) {
+insitem(struct item *it, char *s) {
struct item *new;
+ char *p, *end;
+
if (!(new = calloc(1, sizeof *new)))
return NULL;
if (it) {
it->next = new;
} else
new->prev = new->next = new;
- new->s = strdup(s);
- new->len = len;
- new->ks = NULL; /* TODO */
+ new->nks = 0;
new->dirty = true;
+
+ for (p = s; ; p = end) {
+ size_t n;
+ char c;
+ KeySym ks;
+
+ n = strspn(p, " ");
+ p = p + n;
+ if (!(n = strcspn(p, " \t"))) {
+ p += strspn(p, " \t");
+ break;
+ }
+
+ end = p + n;
+ c = *end;
+ *end = '\0';
+
+ if ((ks = XStringToKeysym(p)) == NoSymbol)
+ warn("no such keysym: %s\n", p);
+ else if (new->nks >= MAXKS)
+ warn("too many keysyms (%s)\n", p);
+ else {
+ KeySym k, dummy;
+ XConvertCase(ks, &k, &dummy);
+ new->ks[new->nks++] = k;
+ }
+
+ *end = c;
+ }
+
+ new->len = strlen(p);
+ new->s = strdup(p);
+
return new;
}
size_t linesize = 0;
ssize_t linelen;
- /* XXX take keysyms into account */
while ((linelen = getline(&line, &linesize, stdin)) != -1) {
struct item *it;
line[--linelen] = '\0'; /* get rid of '\n' */
- if (!(it = insitem(last, line, linelen)))
+ if (!(it = insitem(last, line)))
die(1, "couldn't insert new item");
n++;
last = it;