X-Git-Url: https://git.subgeniuskitty.com/xmenu/.git/blobdiff_plain/7bdb3b0bf8d5540c5736bb339ea9b623a3cab2e2..88341d204bd1ad3f95943190a6eea22cb4bf07da:/xmenu.c diff --git a/xmenu.c b/xmenu.c index f597aeb..8658a9d 100644 --- a/xmenu.c +++ b/xmenu.c @@ -1158,22 +1158,75 @@ append(char *text, char *buf, size_t textsize, size_t buflen) return 1; } -/* get item in menu matching text */ +/* get item in menu matching text from given direction (or from beginning, if dir = 0) */ static struct Item * -matchitem(struct Menu *menu, char *text) +matchitem(struct Menu *menu, char *text, int dir) { - struct Item *item; + struct Item *item, *lastitem; char *s; size_t textlen; + for (lastitem = menu->list; lastitem && lastitem->next; lastitem = lastitem->next) + ; textlen = strlen(text); - for (item = menu->list; item; item = item->next) + if (dir < 0) { + if (menu->selected && menu->selected->prev) + item = menu->selected->prev; + else + item = lastitem; + } else if (dir > 0) { + if (menu->selected && menu->selected->next) + item = menu->selected->next; + else + item = menu->list; + } else { + item = menu->list; + } + /* find next item from selected item */ + for ( ; item; item = (dir < 0) ? item->prev : item->next) for (s = item->label; s && *s; s++) if (strncasecmp(s, text, textlen) == 0) return item; + /* if not found, try to find from the beginning/end of list */ + if (dir > 0) { + for (item = menu->list ; item; item = item->next) { + for (s = item->label; s && *s; s++) { + if (strncasecmp(s, text, textlen) == 0) { + return item; + } + } + } + } else { + for (item = lastitem ; item; item = item->prev) { + for (s = item->label; s && *s; s++) { + if (strncasecmp(s, text, textlen) == 0) { + return item; + } + } + } + } return NULL; } +/* check keysyms defined on config.h */ +static KeySym +normalizeksym(KeySym ksym) +{ + if (ksym == KSYMFIRST) + return XK_Home; + if (ksym == KSYMLAST) + return XK_End; + if (ksym == KSYMUP) + return XK_Up; + if (ksym == KSYMDOWN) + return XK_Down; + if (ksym == KSYMLEFT) + return XK_Left; + if (ksym == KSYMRIGHT) + return XK_Right; + return ksym; +} + /* run event loop */ static void run(struct Menu *currmenu) @@ -1189,6 +1242,7 @@ run(struct Menu *currmenu) XEvent ev; int action; int len; + int i; text[0] = '\0'; mapmenu(currmenu); @@ -1214,7 +1268,7 @@ run(struct Menu *currmenu) } else { currmenu = menu; } - action = ACTION_SELECT | ACTION_MAP | ACTION_DRAW; + action = ACTION_CLEAR | ACTION_SELECT | ACTION_MAP | ACTION_DRAW; break; case ButtonRelease: if (!isclickbutton(ev.xbutton.button)) @@ -1233,7 +1287,7 @@ enteritem: return; } select = currmenu->list; - action = ACTION_SELECT | ACTION_MAP | ACTION_DRAW; + action = ACTION_CLEAR | ACTION_SELECT | ACTION_MAP | ACTION_DRAW; break; case ButtonPress: menu = getmenu(currmenu, ev.xbutton.window); @@ -1261,50 +1315,83 @@ enteritem: ksym = XK_ISO_Left_Tab; /* cycle through menu */ - item = NULL; - if (ksym == XK_Home || ksym == KSYMFIRST) { - item = itemcycle(currmenu, ITEMFIRST); - } else if (ksym == XK_End || ksym == KSYMLAST) { - item = itemcycle(currmenu, ITEMLAST); - } else if (ksym == XK_ISO_Left_Tab || ksym == XK_Up || ksym == KSYMUP) { - item = itemcycle(currmenu, ITEMPREV); - } else if (ksym == XK_Tab || ksym == XK_Down || ksym == KSYMDOWN) { - item = itemcycle(currmenu, ITEMNEXT); - } else if (ksym >= XK_1 && ksym <= XK_9){ + select = NULL; + ksym = normalizeksym(ksym); + switch (ksym) { + case XK_Home: + select = itemcycle(currmenu, ITEMFIRST); + action = ACTION_CLEAR | ACTION_SELECT | ACTION_DRAW; + break; + case XK_End: + select = itemcycle(currmenu, ITEMLAST); + action = ACTION_CLEAR | ACTION_SELECT | ACTION_DRAW; + break; + case XK_ISO_Left_Tab: + if (*text) { + select = matchitem(currmenu, text, -1); + action = ACTION_SELECT | ACTION_DRAW; + break; + } + /* FALLTHROUGH */ + case XK_Up: + select = itemcycle(currmenu, ITEMPREV); + action = ACTION_CLEAR | ACTION_SELECT | ACTION_DRAW; + break; + case XK_Tab: + if (*text) { + select = matchitem(currmenu, text, 1); + action = ACTION_SELECT | ACTION_DRAW; + break; + } + /* FALLTHROUGH */ + case XK_Down: + select = itemcycle(currmenu, ITEMNEXT); + action = ACTION_CLEAR | ACTION_SELECT | ACTION_DRAW; + break; + case XK_1: case XK_2: case XK_3: case XK_4: case XK_5: case XK_6: case XK_7: case XK_8: case XK_9: item = itemcycle(currmenu, ITEMFIRST); lastitem = itemcycle(currmenu, ITEMLAST); for (int i = ksym - XK_1; i > 0 && item != lastitem; i--) { currmenu->selected = item; item = itemcycle(currmenu, ITEMNEXT); } - } else if ((ksym == XK_Return || ksym == XK_Right || ksym == KSYMRIGHT) && - currmenu->selected != NULL) { - item = currmenu->selected; - goto enteritem; - } else if ((ksym == XK_Escape || ksym == XK_Left || ksym == KSYMLEFT) && - currmenu->parent != NULL) { - item = currmenu->parent->selected; - currmenu = currmenu->parent; - action = ACTION_MAP; - } else { + select = item; + action = ACTION_CLEAR | ACTION_SELECT | ACTION_DRAW; + break; + case XK_Return: case XK_Right: + if (currmenu->selected) { + item = currmenu->selected; + goto enteritem; + } + break; + case XK_Escape: case XK_Left: + if (currmenu->parent) { + select = currmenu->parent->selected; + currmenu = currmenu->parent; + action = ACTION_CLEAR | ACTION_MAP | ACTION_SELECT | ACTION_DRAW; + } + break; + case XK_BackSpace: case XK_Clear: case XK_Delete: + action = ACTION_CLEAR | ACTION_SELECT | ACTION_DRAW; + break; + default: append: - if (append(text, buf, sizeof text, len)) { - if ((currmenu->selected = matchitem(currmenu, text))) { - action = ACTION_DRAW; + if (*buf == '\0' || iscntrl(*buf)) + break; + for (i = 0; i < 2; i++) { + append(text, buf, sizeof text, len); + if ((select = matchitem(currmenu, text, 0))) break; - } + text[0] = '\0'; } - select = NULL; action = ACTION_SELECT | ACTION_DRAW; break; } - select = item; - action |= ACTION_SELECT | ACTION_DRAW; break; case LeaveNotify: previtem = NULL; select = NULL; - action = ACTION_SELECT | ACTION_DRAW; + action = ACTION_CLEAR | ACTION_SELECT | ACTION_DRAW; break; case ConfigureNotify: menu = getmenu(currmenu, ev.xconfigure.window); @@ -1324,10 +1411,10 @@ append: action = ACTION_MAP; break; } - if (action & ACTION_SELECT) { - currmenu->selected = select; + if (action & ACTION_CLEAR) text[0] = '\0'; - } + if (action & ACTION_SELECT) + currmenu->selected = select; if (action & ACTION_MAP) mapmenu(currmenu); if (action & ACTION_DRAW) @@ -1402,7 +1489,7 @@ main(int argc, char *argv[]) if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL) errx(1, "XOpenIM: could not open input device"); - /* get configuration */ + /* process configuration and window class */ getresources(); classh.res_class = PROGNAME; classh.res_name = getoptions(argc, argv);