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:
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;
}