wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

commit 5dfffa855ba91a1f53f8cdd4b18ae5ea1392876c
parent 6ce19c39992b9f6869e0619aebfe1842102fe217
Author: Sander van Dijk <sander@wmii.de>
Date:   Fri, 10 Feb 2006 23:57:21 +0100

new wmiimenu, reads a list of newline-separated items from stdin,
and prints the user's selection on stdout. It seems to behave pretty well,
but some of the code definitaly needs a beauty makeover, I'll do that ASAP.


Diffstat:
cmd/Makefile | 3+--
cmd/wmiimenu.1 | 18++----------------
cmd/wmiimenu.c | 408++++++++++++++++++++++++-------------------------------------------------------
3 files changed, 128 insertions(+), 301 deletions(-)

diff --git a/cmd/Makefile b/cmd/Makefile @@ -18,8 +18,7 @@ OBJ_plumb = ${SRC_plumb:.c=.o} SRC_warp = wmiiwarp.c OBJ_warp = ${SRC_warp:.c=.o} -#all: wmiimenu wmiir wmiiplumb wmiiwarp -all: wmiir wmiiplumb wmiiwarp +all: wmiimenu wmiir wmiiplumb wmiiwarp @echo built wmii commands .c.o: diff --git a/cmd/wmiimenu.1 b/cmd/wmiimenu.1 @@ -11,28 +11,14 @@ wmiimenu \- window manager improved 2 menu is a generic, highly customizable, and efficient menu for the X Window System, originally designed for .BR wmii (1). -It supports arbitrary, user defined menu contents, which get executed. -Like wmii, -.B wmiimenu -also implements a socket-based fileserver, which is accessed to configure and -interoperate with other components. +It supports arbitrary, user defined menu contents, which get printed to stdout when selected. .SS Options .TP -.BI \-s " socketfile" -specifies the socketfile that -.B wmiimenu -should create. -.TP .B \-v prints version information to stderr, then exits. .SS Customization .B wmiimenu -is customized through manipulating its filesystem namespace. -In the default setup of -.BR wmii (1) -the namespace of -.B wmiimenu -can be found in /menu. +is customized by feeding it a list of newline-separated items from stdin. .SH SEE ALSO .BR wmiibar (1), .BR wmiifs (1), diff --git a/cmd/wmiimenu.c b/cmd/wmiimenu.c @@ -1,5 +1,6 @@ /* * (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> + * (C)opyright MMVI Sander van Dijk <a dot h dot vandijk at gmail dot com> * See LICENSE file for license details. */ @@ -10,6 +11,7 @@ #include <sys/stat.h> #include <sys/wait.h> #include <time.h> +#include <unistd.h> #include <X11/Xlib.h> #include <X11/Xatom.h> #include <X11/cursorfont.h> @@ -17,25 +19,8 @@ #include <X11/Xutil.h> #include <X11/keysym.h> -#include "wmii.h" - -/* array indexes for file pointers */ -typedef enum { - M_CTL, - M_GEOMETRY, - M_PRE_COMMAND, - M_COMMAND, - M_HISTORY, - M_LOOKUP, - M_FONT, - M_SEL_BG_COLOR, - M_SEL_TEXT_COLOR, - M_SEL_BORDER_COLOR, - M_NORM_BG_COLOR, - M_NORM_TEXT_COLOR, - M_NORM_BORDER_COLOR, - M_LAST -} InputIndexes; +#include "blitz.h" + enum { OFF_NEXT, OFF_PREV, OFF_CURR, OFF_LAST @@ -43,102 +28,62 @@ enum { typedef struct Item Item; struct Item { - File *file; + char *name; Item *next; Item *prev; }; -static IXPServer *ixps = 0; +static char *command = 0; +static Item *allitems = nil; +static char *fontstr = 0; +static char *normcolstr = 0; +static char *selcolstr = 0; +static int done = 0; +static int retvalue = 0; + static Display *dpy; static GC gc; static Window win; static XRectangle rect; static XRectangle mrect; static int screen; -static char *sockfile = 0; -static File *files[M_LAST]; static size_t nitems = 0; static Item *sel = nil; static Item *items = nil; -static Item *selhist = nil; -static Item *history = nil; static Item *offset[OFF_LAST]; static unsigned int cmdw = 0; static Pixmap pmap; static const int seek = 30; /* 30px */ static XFontStruct *font; -static Align align = SOUTH; -static void check_event(Connection * c); +static void check_event(void); static void draw_menu(void); static void handle_kpress(XKeyEvent * e); static void set_text(char *text); -static void quit(void *obj, char *arg); -static void display(void *obj, char *arg); static size_t update_items(char *prefix); -static Action acttbl[2] = { - {"quit", quit}, - {"display", display} -}; - static char version[] = "wmiimenu - " VERSION ", (C)opyright MMIV-MMVI Anselm R. Garbe\n"; static void usage() { - fprintf(stderr, "%s", "usage: wmiimenu [-a <address>] [-r] [-v]\n"); + fprintf(stderr, "%s", "usage: wmiimenu [-v]\n"); exit(1); } static void -add_history(char *cmd) -{ - Item *h, *new; - char buf[MAX_BUF]; - snprintf(buf, MAX_BUF, "/history/%ld", (long) time(0)); - - new = cext_emallocz(sizeof(Item)); - new->file = wmii_create_ixpfile(ixps, buf, cmd); - for(h = history; h && h->next; h = h->next); - if(!h) - history = new; - else { - h->next = new; - new->prev = h; - } - selhist = new; -} - -static void -exec_item(char *cmd) +return_item(char *cmd) { char *rc = cmd; if(!cmd || cmd[0] == 0) return; - if(sel && sel->file->size) - rc = cmd = sel->file->content; - add_history(cmd); + if(sel && strlen(sel->name)) + rc = cmd = sel->name; - if(files[M_PRE_COMMAND]->content) { - size_t len = strlen(cmd) + files[M_PRE_COMMAND]->size + 2; - rc = cext_emallocz(len); - snprintf(rc, len, "%s %s", (char *) files[M_PRE_COMMAND]->content, - cmd); - } - /* fallback */ - wmii_spawn(dpy, rc); - /* cleanup */ - if(files[M_PRE_COMMAND]->content) - free(rc); -} - -static void -quit(void *obj, char *arg) -{ - ixps->runlevel = SHUTDOWN; + fprintf(stdout, "%s", rc); + done = 1; } static void @@ -147,12 +92,13 @@ show() set_text(0); XMapRaised(dpy, win); XSync(dpy, False); - update_items(files[M_COMMAND]->content); + update_items(command); draw_menu(); while(XGrabKeyboard (dpy, RootWindow(dpy, screen), True, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) - usleep(1000); + usleep(1000); + } static void @@ -163,29 +109,15 @@ hide() XSync(dpy, False); } -static void -display(void *obj, char *arg) -{ - if(!arg) - return; - if(blitz_strtonum(arg, 0, 1)) - show(); - else - hide(); - check_event(0); -} - void set_text(char *text) { - if(files[M_COMMAND]->content) { - free(files[M_COMMAND]->content); - files[M_COMMAND]->content = 0; - files[M_COMMAND]->size = 0; + if(command) { + free(command); + command = 0; } if(text && strlen(text)) { - files[M_COMMAND]->content = strdup(text); - files[M_COMMAND]->size = strlen(text); + command = strdup(text); } } @@ -200,8 +132,8 @@ update_offsets() /* calc next offset */ for(i = offset[OFF_CURR]; i; i = i->next) { - w += XTextWidth(font, i->file->content, - strlen(i->file->content)) + mrect.height; + w += XTextWidth(font, i->name, + strlen(i->name)) + mrect.height; if(w > mrect.width) break; } @@ -209,8 +141,8 @@ update_offsets() w = cmdw + 2 * seek; for(i = offset[OFF_CURR]->prev; i && i->prev; i = i->prev) { - w += XTextWidth(font, i->file->content, - strlen(i->file->content)) + mrect.height; + w += XTextWidth(font, i->name, + strlen(i->name)) + mrect.height; if(w > mrect.width) break; } @@ -222,14 +154,7 @@ update_items(char *pattern) { size_t plen = pattern ? strlen(pattern) : 0, len, max = 0; int matched = pattern ? plen == 0 : 1; - File *f, *p, *maxitem; - Item *i, *new; - - if(!files[M_LOOKUP]->content) - return 0; - f = ixp_walk(ixps, files[M_LOOKUP]->content); - if(!f || !is_directory(f)) - return 0; + Item *i, *new, *p, *maxitem = 0; cmdw = 0; offset[OFF_CURR] = offset[OFF_PREV] = offset[OFF_NEXT] = nil; @@ -242,7 +167,7 @@ update_items(char *pattern) nitems = 0; /* build new items */ - for(p = f->content; p; p = p->next) { + for(p = allitems; p; p = p->next) { len = strlen(p->name); if(max < len) { maxitem = p; @@ -253,36 +178,40 @@ update_items(char *pattern) if(maxitem) cmdw = XTextWidth(font, maxitem->name, max) + mrect.height; - for(p = f->content; p; p = p->next) { + for(p = allitems; p; p = p->next) { if(matched || !strncmp(pattern, p->name, plen)) { new = cext_emallocz(sizeof(Item)); - new->file = p; + new->name = strdup(p->name); + new->next=0; + new->prev=0; nitems++; if(!items) offset[OFF_CURR] = sel = items = i = new; - else { + else { i->next = new; new->prev = i; i = new; } - p->parent = 0; /* HACK to prevent doubled items */ } } - - for(p = f->content; p; p = p->next) { - if(p->parent && strstr(p->name, pattern)) { + + for(p = allitems; p; p = p->next) { + if(pattern && strstr(p->name, pattern)) { new = cext_emallocz(sizeof(Item)); - new->file = p; + new->name = strdup(p->name); + new->next=0; + new->prev=0; nitems++; if(!items) offset[OFF_CURR] = sel = items = i = new; else { - i->next = new; - new->prev = i; - i = new; + if(strncmp(pattern, p->name, plen)) { /* yuck... */ + i->next = new; + new->prev = i; + i = new; + } } - } else - p->parent = f; /* restore HACK */ + } } update_offsets(); @@ -303,20 +232,13 @@ draw_menu() d.rect = mrect; d.rect.x = 0; d.rect.y = 0; - d.bg = - blitz_loadcolor(dpy, screen, files[M_NORM_BG_COLOR]->content); - d.border = - blitz_loadcolor(dpy, screen, - files[M_NORM_BORDER_COLOR]->content); + blitz_loadcolor(dpy, screen, normcolstr, &(d.color)); blitz_drawlabelnoborder(dpy, &d); /* print command */ d.align = WEST; d.font = font; - d.fg = - blitz_loadcolor(dpy, screen, - files[M_NORM_TEXT_COLOR]->content); - d.data = files[M_COMMAND]->content; + d.data = command; if(cmdw && sel) d.rect.width = cmdw; offx += d.rect.width; @@ -324,12 +246,7 @@ draw_menu() d.align = CENTER; if(sel) { - d.bg = - blitz_loadcolor(dpy, screen, - files[M_NORM_BG_COLOR]->content); - d.fg = - blitz_loadcolor(dpy, screen, - files[M_NORM_TEXT_COLOR]->content); + blitz_loadcolor(dpy, screen, normcolstr, &(d.color)); d.data = offset[OFF_PREV] ? "<" : nil; d.rect.x = offx; d.rect.width = seek; @@ -338,43 +255,21 @@ draw_menu() /* determine maximum items */ for(i = offset[OFF_CURR]; i && i != offset[OFF_NEXT]; i = i->next) { - d.data = i->file->name; + d.data = i->name; d.rect.x = offx; d.rect.width = XTextWidth(d.font, d.data, strlen(d.data)) + mrect.height; offx += d.rect.width; - /*fprintf(stderr, "%s (%d, %d, %d, %d)\n", item->name, d.rect.x, d.rect.y, d.rect.width, d.rect.height); */ if(sel == i) { - d.bg = - blitz_loadcolor(dpy, screen, - files[M_SEL_BG_COLOR]->content); - d.fg = - blitz_loadcolor(dpy, screen, - files[M_SEL_TEXT_COLOR]->content); - d.border = - blitz_loadcolor(dpy, screen, - files[M_SEL_BORDER_COLOR]->content); + blitz_loadcolor(dpy, screen, selcolstr, &(d.color)); blitz_drawlabel(dpy, &d); } else { - d.bg = - blitz_loadcolor(dpy, screen, - files[M_NORM_BG_COLOR]->content); - d.fg = - blitz_loadcolor(dpy, screen, - files[M_NORM_TEXT_COLOR]->content); - d.border = - blitz_loadcolor(dpy, screen, - files[M_NORM_BORDER_COLOR]->content); + blitz_loadcolor(dpy, screen, normcolstr, &(d.color)); blitz_drawlabelnoborder(dpy, &d); } } - d.bg = - blitz_loadcolor(dpy, screen, - files[M_NORM_BG_COLOR]->content); - d.fg = - blitz_loadcolor(dpy, screen, - files[M_NORM_TEXT_COLOR]->content); + blitz_loadcolor(dpy, screen, normcolstr, &(d.color)); d.data = offset[OFF_NEXT] ? ">" : nil; d.rect.x = mrect.width - seek; d.rect.width = seek; @@ -394,8 +289,8 @@ handle_kpress(XKeyEvent * e) size_t len = 0; text[0] = 0; - if(files[M_COMMAND]->content) { - cext_strlcpy(text, files[M_COMMAND]->content, sizeof(text)); + if(command) { + cext_strlcpy(text, command, sizeof(text)); len = strlen(text); } buf[0] = 0; @@ -448,8 +343,8 @@ handle_kpress(XKeyEvent * e) case XK_Tab: if(!sel) return; - set_text(sel->file->name); - update_items(files[M_COMMAND]->content); + set_text(sel->name); + update_items(command); break; case XK_Right: if(!sel) @@ -459,29 +354,15 @@ handle_kpress(XKeyEvent * e) } else return; break; - case XK_Down: - if(selhist) { - set_text(selhist->file->content); - if(selhist->next) - selhist = selhist->next; - } - update_items(files[M_COMMAND]->content); - break; - case XK_Up: - if(selhist) { - set_text(selhist->file->content); - if(selhist->prev) - selhist = selhist->prev; - } - update_items(files[M_COMMAND]->content); - break; case XK_Return: if(sel) - exec_item(sel->file->name); + return_item(sel->name); else if(text) - exec_item(text); + return_item(text); + break; case XK_Escape: - hide(); + retvalue = 1; + done = 1; break; case XK_BackSpace: if(len) { @@ -493,7 +374,7 @@ handle_kpress(XKeyEvent * e) while((prev_nitems = nitems) && i && prev_nitems == update_items(text)); } set_text(text); - update_items(files[M_COMMAND]->content); + update_items(command); } break; default: @@ -504,7 +385,7 @@ handle_kpress(XKeyEvent * e) else cext_strlcpy(text, buf, sizeof(text)); set_text(text); - update_items(files[M_COMMAND]->content); + update_items(command); } } if(sel) { @@ -520,7 +401,7 @@ handle_kpress(XKeyEvent * e) } static void -check_event(Connection * c) +check_event() { XEvent ev; @@ -546,8 +427,7 @@ update_geometry() { mrect = rect; mrect.height = font->ascent + font->descent + 4; - if(align == SOUTH) - mrect.y = rect.height - mrect.height; + mrect.y = rect.height - mrect.height; XMoveResizeWindow(dpy, win, mrect.x, mrect.y, mrect.width, mrect.height); XSync(dpy, False); @@ -558,59 +438,37 @@ update_geometry() XSync(dpy, False); } -static void -handle_after_write(IXPServer * s, File * f) +void +init_allitems() { - int i; - size_t len; - - if(files[M_CTL] == f) { - for(i = 0; i < 2; i++) { - len = strlen(acttbl[i].name); - if(!strncmp(acttbl[i].name, (char *) f->content, len)) { - if(strlen(f->content) > len) { - acttbl[i].func(0, &((char *) f->content)[len + 1]); - } else { - acttbl[i].func(0, 0); - } - break; - } + char text[4096]; + allitems = cext_emallocz(sizeof(Item)); + allitems->prev = 0; + Item *curitem = allitems; + char ch; + int i = 0; + while ((ch = (char)fgetc(stdin)) != EOF) { + if (!iscntrl(ch) && i<4095) { + text[i]=ch; + i++; + } else { + text[i] = 0; + if (strlen(text)) { + curitem->name = strdup(text); + curitem->next = cext_emallocz(sizeof(Item)); + curitem->next->prev = curitem; + curitem = curitem->next; + } + i=0; } - } else if(files[M_GEOMETRY] == f) { - if(f->content) { - if(!strncmp(f->content, "south", 6)) - align = SOUTH; - else if(!strncmp(f->content, "north", 6)) - align = NORTH; - update_geometry(); - draw_menu(); - } - } else if(files[M_FONT] == f) { - XFreeFont(dpy, font); - font = blitz_getfont(dpy, files[M_FONT]->content); - update_geometry(); - draw_menu(); - } else if(files[M_COMMAND] == f) { - update_items(files[M_COMMAND]->content); - draw_menu(); } - check_event(0); -} - -static void -handle_before_read(IXPServer * s, File * f) -{ - char buf[64]; - if(f != files[M_GEOMETRY]) - return; - snprintf(buf, sizeof(buf), "%d %d %d %d", mrect.x, mrect.y, - mrect.width, mrect.height); - if(f->content) - free(f->content); - f->content = strdup(buf); - f->size = strlen(buf); + if (curitem == allitems) + allitems = 0; + if (curitem->prev) + curitem->prev->next = 0; + free(curitem); } - + int main(int argc, char *argv[]) { @@ -622,15 +480,9 @@ main(int argc, char *argv[]) for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) { switch (argv[i][1]) { case 'v': - fprintf(stdout, "%s", version[0]); + fprintf(stdout, "%s", version); exit(0); break; - case 's': - if(i + 1 < argc) - sockfile = argv[++i]; - else - usage(); - break; default: usage(); break; @@ -644,41 +496,19 @@ main(int argc, char *argv[]) } screen = DefaultScreen(dpy); - ixps = wmii_setup_server(sockfile); + /* set font and colors */ + fontstr = getenv("WMII_FONT"); + if (!fontstr) + fontstr = strdup(BLITZ_FONT); + font = blitz_getfont(dpy, fontstr); + normcolstr = getenv("WMII_NORMCOLORS"); + if (!normcolstr || strlen(normcolstr) != 23) + normcolstr = strdup(BLITZ_NORMCOLORS); + selcolstr = getenv("WMII_SELCOLORS"); + if (!selcolstr || strlen(selcolstr) != 23) + selcolstr = strdup(BLITZ_SELCOLORS); /* init */ - if(!(files[M_CTL] = ixp_create(ixps, "/ctl"))) { - perror("wmiimenu: cannot connect IXP server"); - exit(1); - } - files[M_CTL]->after_write = handle_after_write; - files[M_GEOMETRY] = ixp_create(ixps, "/geometry"); - files[M_GEOMETRY]->before_read = handle_before_read; - files[M_GEOMETRY]->after_write = handle_after_write; - files[M_PRE_COMMAND] = ixp_create(ixps, "/precmd"); - files[M_COMMAND] = ixp_create(ixps, "/cmd"); - files[M_COMMAND]->after_write = handle_after_write; - files[M_HISTORY] = ixp_create(ixps, "/history"); - add_history(""); - files[M_LOOKUP] = ixp_create(ixps, "/lookup"); - files[M_FONT] = wmii_create_ixpfile(ixps, "/font", BLITZ_FONT); - files[M_FONT]->after_write = handle_after_write; - font = blitz_getfont(dpy, files[M_FONT]->content); - files[M_SEL_BG_COLOR] = - wmii_create_ixpfile(ixps, "/sstyle/bgcolor", BLITZ_SEL_BG_COLOR); - files[M_SEL_TEXT_COLOR] = - wmii_create_ixpfile(ixps, "/sstyle/fgcolor", BLITZ_SEL_FG_COLOR); - files[M_SEL_BORDER_COLOR] = - wmii_create_ixpfile(ixps, "/sstyle/bordercolor", - BLITZ_SEL_BORDER_COLOR); - files[M_NORM_BG_COLOR] = - wmii_create_ixpfile(ixps, "/nstyle/bgcolor", BLITZ_NORM_BG_COLOR); - files[M_NORM_TEXT_COLOR] = - wmii_create_ixpfile(ixps, "/nstyle/fgcolor", BLITZ_NORM_FG_COLOR); - files[M_NORM_BORDER_COLOR] = - wmii_create_ixpfile(ixps, "/nstyle/bordercolor", - BLITZ_NORM_BORDER_COLOR); - wa.override_redirect = 1; wa.background_pixmap = ParentRelative; wa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask @@ -709,13 +539,25 @@ main(int argc, char *argv[]) XCreatePixmap(dpy, win, mrect.width, mrect.height, DefaultDepth(dpy, screen)); + /* initialize some more stuff */ + update_geometry(); + init_allitems(); + if(!allitems) { + fprintf(stderr, "%s", "wmiimenu: feed me newline-separated items on stdin please.\n"); + exit(1); + } + /* main event loop */ - run_server_with_fd_support(ixps, ConnectionNumber(dpy), check_event, - 0); - deinit_server(ixps); + show(); + while (!done) { + check_event(); + usleep(1000); + } + hide(); + XFreePixmap(dpy, pmap); XFreeGC(dpy, gc); XCloseDisplay(dpy); - return 0; + return retvalue; }