wmii

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

commit f53b8d61ef0065d23509b47e6671aefa2eec40ad
parent 1f3ecb5a7c2289fbf17de5a7665088ea9401696d
Author: garbeam <garbeam@mmv.wmii.de>
Date:   Mon, 12 Dec 2005 16:08:16 +0200

renamed all wmi* prefixed tools into wmii* prefixed ones to prevent further confusion


Diffstat:
Makefile | 8++++----
cmd/Makefile | 44++++++++++++++++++++++----------------------
cmd/wm/wmii | 18+++++++++---------
cmd/wmibar.1 | 43-------------------------------------------
cmd/wmibar.c | 534-------------------------------------------------------------------------------
cmd/wmibar2.c | 449-------------------------------------------------------------------------------
cmd/wmifs.1 | 38--------------------------------------
cmd/wmifs.c | 376-------------------------------------------------------------------------------
cmd/wmiibar.1 | 43+++++++++++++++++++++++++++++++++++++++++++
cmd/wmiibar.c | 534+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmiibar2.c | 449+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmiifs.1 | 38++++++++++++++++++++++++++++++++++++++
cmd/wmiifs.c | 376+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmiikeys.1 | 45+++++++++++++++++++++++++++++++++++++++++++++
cmd/wmiikeys.c | 481+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmiimenu.1 | 42++++++++++++++++++++++++++++++++++++++++++
cmd/wmiimenu.c | 621+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmiiplumb.c | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmiir.1 | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmiir.c | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmiir2.c | 243+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmiiwarp.c | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wmikeys.1 | 45---------------------------------------------
cmd/wmikeys.c | 481-------------------------------------------------------------------------------
cmd/wmimenu.1 | 42------------------------------------------
cmd/wmimenu.c | 621-------------------------------------------------------------------------------
cmd/wmiplumb.c | 92-------------------------------------------------------------------------------
cmd/wmir.1 | 71-----------------------------------------------------------------------
cmd/wmir.c | 225-------------------------------------------------------------------------------
cmd/wmir2.c | 243-------------------------------------------------------------------------------
cmd/wmiwarp.c | 54------------------------------------------------------
rc/kmode | 10+++++-----
rc/quit | 2+-
rc/status | 14+++++++-------
rc/welcome | 4++--
rc/wmiirc | 170+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
rc/wmirc | 170-------------------------------------------------------------------------------
37 files changed, 3534 insertions(+), 3534 deletions(-)

diff --git a/Makefile b/Makefile @@ -5,11 +5,11 @@ include config.mk SUBDIRS = libcext liblitz libixp libixp2 libwmii cmd -BIN = cmd/wm/wmii cmd/wm/wmiiwm cmd/wmibar cmd/wmifs \ - cmd/wmikeys cmd/wmimenu cmd/wmiplumb cmd/wmir cmd/wmiwarp +BIN = cmd/wm/wmii cmd/wm/wmiiwm cmd/wmiibar cmd/wmiifs \ + cmd/wmiikeys cmd/wmiimenu cmd/wmiiplumb cmd/wmiir cmd/wmiiwarp -MAN1 = cmd/wm/wmii.1 cmd/wm/wmiiwm.1 cmd/wmibar.1 cmd/wmifs.1 \ - cmd/wmikeys.1 cmd/wmimenu.1 cmd/wmir.1 +MAN1 = cmd/wm/wmii.1 cmd/wm/wmiiwm.1 cmd/wmiibar.1 cmd/wmiifs.1 \ + cmd/wmiikeys.1 cmd/wmiimenu.1 cmd/wmiir.1 all: @echo wmii build options: diff --git a/cmd/Makefile b/cmd/Makefile @@ -9,78 +9,78 @@ LDFLAGS += -L../liblitz -llitz -L../libixp -lixp \ LDFLAGS2 += ${LIBS} -L../liblitz -llitz -L../libixp2 -lixp \ -L../libwmii -lwmii -L../libcext -lcext -SRC_bar = wmibar.c +SRC_bar = wmiibar.c OBJ_bar = ${SRC_bar:.c=.o} -SRC_bar2 = wmibar2.c +SRC_bar2 = wmiibar2.c OBJ_bar2 = ${SRC_bar2:.c=.o} -SRC_menu = wmimenu.c +SRC_menu = wmiimenu.c OBJ_menu = ${SRC_menu:.c=.o} -SRC_r2 = wmir2.c +SRC_r2 = wmiir2.c OBJ_r2 = ${SRC_r2:.c=.o} -SRC_r = wmir.c +SRC_r = wmiir.c OBJ_r = ${SRC_r:.c=.o} -SRC_fs = wmifs.c +SRC_fs = wmiifs.c OBJ_fs = ${SRC_fs:.c=.o} -SRC_keys = wmikeys.c +SRC_keys = wmiikeys.c OBJ_keys = ${SRC_keys:.c=.o} -SRC_plumb = wmiplumb.c +SRC_plumb = wmiiplumb.c OBJ_plumb = ${SRC_plumb:.c=.o} -SRC_warp = wmiwarp.c +SRC_warp = wmiiwarp.c OBJ_warp = ${SRC_warp:.c=.o} -all: wmibar wmibar2 wmimenu wmir wmir2 wmifs wmikeys wmiplumb wmiwarp - @echo built wmi commands +all: wmiibar wmiibar2 wmiimenu wmiir wmiir2 wmiifs wmiikeys wmiiplumb wmiiwarp + @echo built wmii commands .c.o: @echo CC $< @${CC} -c ${CFLAGS} $< -wmibar: ${OBJ_bar} +wmiibar: ${OBJ_bar} @echo LD $@ @${CC} -o $@ ${OBJ_bar} ${LDFLAGS} -wmibar2: ${OBJ_bar2} +wmiibar2: ${OBJ_bar2} @echo LD $@ @${CC} -o $@ ${OBJ_bar2} ${LDFLAGS2} -wmimenu: ${OBJ_menu} +wmiimenu: ${OBJ_menu} @echo LD $@ @${CC} -o $@ ${OBJ_menu} ${LDFLAGS} -wmir2: ${OBJ_r2} +wmiir2: ${OBJ_r2} @echo LD $@ @${CC} -o $@ ${OBJ_r2} -g -static -L${LIBDIR} -L/usr/lib -lc \ -L../libixp2 -lixp -L../libcext -lcext -wmir: ${OBJ_r} +wmiir: ${OBJ_r} @echo LD $@ @${CC} -o $@ ${OBJ_r} -g -static -L${LIBDIR} -L/usr/lib -lc \ -L../libixp -lixp -L../libcext -lcext -wmifs: ${OBJ_fs} +wmiifs: ${OBJ_fs} @echo LD $@ @${CC} -o $@ ${OBJ_fs} ${LDFLAGS} -wmikeys: ${OBJ_keys} +wmiikeys: ${OBJ_keys} @echo LD $@ @${CC} -o $@ ${OBJ_keys} ${LDFLAGS} -wmiplumb: ${OBJ_plumb} +wmiiplumb: ${OBJ_plumb} @echo LD $@ @${CC} -o $@ ${OBJ_plumb} ${LDFLAGS} -wmiwarp: ${OBJ_warp} +wmiiwarp: ${OBJ_warp} @echo LD $@ @${CC} -o $@ ${OBJ_warp} ${LDFLAGS} clean: - rm -f wmibar wmibar2 wmimenu wmir wmir2 wmikeys wmiplumb wmifs\ - wmiwarp *.o + rm -f wmiibar wmiibar2 wmiimenu wmiir wmiir2 wmiikeys wmiiplumb wmiifs\ + wmiiwarp *.o diff --git a/cmd/wm/wmii b/cmd/wm/wmii @@ -19,17 +19,17 @@ WMIR_SOCKET=/tmp/.ixp-$USER/wmifs-$WMII_IDENT mkdir -p /tmp/.ixp-$USER wmiiwm -s /tmp/.ixp-$USER/wmiiwm-$WMII_IDENT & wmiiwmpid=$apid -wmifs -s /tmp/.ixp-$USER/wmifs-$WMII_IDENT & -wmikeys -s /tmp/.ixp-$USER/wmikeys-$WMII_IDENT & -wmibar -s /tmp/.ixp-$USER/wmibar-$WMII_IDENT & -wmimenu -s /tmp/.ixp-$USER/wmimenu-$WMII_IDENT & +wmiifs -s /tmp/.ixp-$USER/wmiifs-$WMII_IDENT & +wmiikeys -s /tmp/.ixp-$USER/wmiikeys-$WMII_IDENT & +wmiibar -s /tmp/.ixp-$USER/wmiibar-$WMII_IDENT & +wmiimenu -s /tmp/.ixp-$USER/wmiimenu-$WMII_IDENT & sleep 1 # mount ixp file systems: -wmir write /ctl 'bind /wm /tmp/.ixp-'^$USER/wmiiwm-$WMII_IDENT -wmir write /ctl 'bind /bar /tmp/.ixp-'^$USER/wmibar-$WMII_IDENT -wmir write /ctl 'bind /menu /tmp/.ixp-'^$USER/wmimenu-$WMII_IDENT -wmir write /ctl 'bind /keys /tmp/.ixp-'^$USER/wmikeys-$WMII_IDENT +wmiir write /ctl 'bind /wm /tmp/.ixp-'^$USER/wmiiwm-$WMII_IDENT +wmiir write /ctl 'bind /bar /tmp/.ixp-'^$USER/wmiibar-$WMII_IDENT +wmiir write /ctl 'bind /menu /tmp/.ixp-'^$USER/wmiimenu-$WMII_IDENT +wmiir write /ctl 'bind /keys /tmp/.ixp-'^$USER/wmiikeys-$WMII_IDENT # display the wmii introduction if necessary: if(mkdir $HOME/.wmii-3 >[2]/dev/null) { @@ -37,7 +37,7 @@ if(mkdir $HOME/.wmii-3 >[2]/dev/null) { } # run configuration: -wmirc & +wmiirc & # wait for wmiiwm's termination: wait $wmiiwmpid diff --git a/cmd/wmibar.1 b/cmd/wmibar.1 @@ -1,43 +0,0 @@ -.TH WMIBAR 1 wmii-3 -.SH NAME -wmibar \- window manager improved 2 bar -.SH SYNOPSIS -.B wmibar -.B \-s -.I socketfile -.SH DESCRIPTION -.SS Overview -.B wmibar -is a generic and highly customizable bar for the X Window System, -originally designed for -.BR wmii (1). -It supports arbitrary sized labels with arbitrary styles on a per label -basis and with button click events. -Like wmii, -.B wmibar -also implements a socket-based fileserver, which is accessed to configure and -interoperate with other components. -.SS Options -.TP -.BI \-s " socketfile" -specifies the socketfile that -.B wmibar -should create. -.TP -.B \-v -prints version information to stderr, then exits. -.SS Customization -.B wmibar -is customized through manipulating its filesystem namespace. -In the default setup of -.BR wmii (1) -the namespace of -.B wmibar -can be found in /bar. -.SH SEE ALSO -.BR wmifs (1), -.BR wmii (1), -.BR wmiiwm (1), -.BR wmikeys (1), -.BR wmimenu (1), -.BR wmir (1) diff --git a/cmd/wmibar.c b/cmd/wmibar.c @@ -1,534 +0,0 @@ -/* - * (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ - -#include <assert.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <X11/Xatom.h> -#include <X11/cursorfont.h> -#include <X11/Xproto.h> -#include <X11/Xutil.h> - -#include "wmii.h" - -/* array indexes for file pointers */ -typedef enum { - B_CTL, - B_NEW, - B_EXPANDABLE, - B_GEOMETRY, - B_FONT, - B_FG_COLOR, - B_BORDER_COLOR, - B_BG_COLOR, - B_LAST -} BarIndexes; - -typedef struct { - File *root; - Draw d; -} Item; - -static unsigned int id = 0; -static IXPServer *ixps = 0; -static Display *dpy; -static GC gc; -static Window win; -static XRectangle rect; -static XRectangle brect; -static int screen_num; -static int displayed = 0; -static char *sockfile = 0; -static File *file[B_LAST]; -static Container items = {0}; -static Pixmap pmap; -static XFontStruct *font; -static Align align = SOUTH; - -static Draw zero_draw = { 0 }; - -static void draw_bar(void *obj, char *arg); -static void quit(void *obj, char *arg); -static void display(void *obj, char *arg); -static void reset(void *obj, char *arg); -static void _destroy(void *obj, char *arg); -static void handle_after_write(IXPServer * s, File * f); - -static Action acttbl[] = { - {"quit", quit}, - {"display", display}, - {"update", draw_bar}, - {"reset", reset}, - {"destroy", _destroy}, - {0, 0} -}; - -static char *version[] = { - "wmibar - window manager improved bar - " VERSION "\n" - " (C)opyright MMIV-MMV Anselm R. Garbe\n", 0 -}; - -static void usage() -{ - fprintf(stderr, "%s", - "usage: wmibar -s <socket file> [-v]\n" - " -s socket file\n" " -v version info\n"); - exit(1); -} - -/** - * <path>/data "<txt value>" - * <path>/fgcolor "#RRGGBBAA" - * <path>/bgcolor "#RRGGBBAA" - * <path>/bordercolor "#RRGGBBAA" - * <path>/b1press "<command>" - * <path>/b2press "<command>" - * <path>/b3press "<command>" - * <path>/b4press "<command>" - * <path>/b5press "<command>" - */ -static void create_label(char *path) -{ - File *f; - char buf[MAX_BUF]; - int i; - - snprintf(buf, MAX_BUF, "%s/data", path); - f = ixp_create(ixps, buf); - f->after_write = handle_after_write; - snprintf(buf, MAX_BUF, "%s/fgcolor", path); - wmii_create_ixpfile(ixps, buf, file[B_FG_COLOR]->content); - snprintf(buf, MAX_BUF, "%s/bgcolor", path); - wmii_create_ixpfile(ixps, buf, file[B_BG_COLOR]->content); - snprintf(buf, MAX_BUF, "%s/bordercolor", path); - wmii_create_ixpfile(ixps, buf, file[B_BORDER_COLOR]->content); - for (i = 1; i < 6; i++) { /* 5 buttons events */ - snprintf(buf, MAX_BUF, "%s/b%dpress", path, i); - ixp_create(ixps, buf); - } -} - -static void _destroy(void *obj, char *arg) -{ - char buf[512]; - if (!arg) - return; - snprintf(buf, sizeof(buf), "/%s", arg); - ixps->remove(ixps, buf); - draw_bar(0, 0); -} - -static void reset(void *obj, char *arg) -{ - int i; - char buf[512]; - for (i = 0; i < id; i++) { - snprintf(buf, sizeof(buf), "/%d", i); - ixps->remove(ixps, buf); - } - id = 0; - draw_bar(0, 0); -} - -static void quit(void *obj, char *arg) -{ - ixps->runlevel = SHUTDOWN; -} - -static void display(void *obj, char *arg) -{ - if (!arg) - return; - displayed = blitz_strtonum(arg, 0, 1); - if (displayed) { - XMapRaised(dpy, win); - draw_bar(0, 0); - } else { - XUnmapWindow(dpy, win); - XSync(dpy, False); - } -} - -static void init_draw_label(char *path, Draw *d) -{ - char buf[MAX_BUF]; - File *f; - - /* text stuff */ - snprintf(buf, MAX_BUF, "%s/data", path); - f = ixp_walk(ixps, buf); - d->data = f->content; - /* style stuff */ - snprintf(buf, MAX_BUF, "%s/fgcolor", path); - f = ixp_walk(ixps, buf); - d->fg = blitz_loadcolor(dpy, screen_num, f->content); - snprintf(buf, MAX_BUF, "%s/bgcolor", path); - f = ixp_walk(ixps, buf); - d->bg = blitz_loadcolor(dpy, screen_num, f->content); - snprintf(buf, MAX_BUF, "%s/bordercolor", path); - f = ixp_walk(ixps, buf); - d->border = blitz_loadcolor(dpy, screen_num, f->content); -} - -static void init_item(char *path, Item *i) -{ - i->d = zero_draw; - i->root = ixp_walk(ixps, path); - i->d.gc = gc; - i->d.drawable = pmap; - i->d.rect = brect; - i->d.rect.y = 0; - init_draw_label(path, &i->d); -} - -static int comp_str(const void *s1, const void *s2) -{ - return strcmp(*(char **) s1, *(char **) s2); -} - -static void draw() -{ - Item *item; - unsigned int i, w, xoff = 0; - unsigned expandable = 0; - char buf[32]; - size_t size = cext_sizeof(&items); - - if (!size) - return; - - expandable = blitz_strtonum(file[B_EXPANDABLE]->content, 0, size); - snprintf(buf, sizeof(buf), "/%d", expandable); - if (!ixp_walk(ixps, buf)) - expandable = 0; - - w = 0; - /* precalc */ - for (i = 0; i < size; i++) - if (i != expandable) { - item = cext_list_get_item(&items, i); - item->d.rect.width = brect.height; - if (item->d.data) { - if (!strncmp(item->d.data, "%m:", 3)) - /* meter */ - item->d.rect.width = brect.height / 2; - else - item->d.rect.width += XTextWidth(font, item->d.data, strlen(item->d.data)); - } - w += item->d.rect.width; - } - if (w > brect.width) { - /* failsafe mode, give all labels same width */ - w = brect.width / size; - for (i = 0; i < size; i++) { - item = cext_list_get_item(&items, i); - item->d.rect.width = w; - } - item->d.rect.width = brect.width - item->d.rect.x; - } - else { - item = cext_list_get_item(&items, expandable); - item->d.rect.width = brect.width - w; - } - for (i = 0; i < size; i++) { - item = cext_list_get_item(&items, i); - item->d.font = font; - item->d.rect.x = xoff; - xoff += item->d.rect.width; - if (item->d.data && !strncmp(item->d.data, "%m:", 3)) - blitz_drawmeter(dpy, &item->d); - else - blitz_drawlabel(dpy, &item->d); - } - XCopyArea(dpy, pmap, win, gc, 0, 0, brect.width, brect.height, 0, 0); - XSync(dpy, False); -} - -static void draw_bar(void *obj, char *arg) -{ - File *label = 0; - unsigned int i = 0, n = 0; - Item *item; - char buf[512]; - - if (!displayed) - return; - while ((item = cext_stack_get_top_item(&items))) { - cext_detach_item(&items, item); - free(item); - } - snprintf(buf, sizeof(buf), "%s", "/0"); - label = ixp_walk(ixps, buf); - if (!label) { - Draw d = { 0 }; - /* default stuff */ - d.gc = gc; - d.drawable = pmap; - d.rect.width = brect.width; - d.rect.height = brect.height; - d.bg = blitz_loadcolor(dpy, screen_num, file[B_BG_COLOR]->content); - d.fg = blitz_loadcolor(dpy, screen_num, file[B_FG_COLOR]->content); - d.border = blitz_loadcolor(dpy, screen_num, file[B_BORDER_COLOR]->content); - blitz_drawlabelnoborder(dpy, &d); - } else { - File *f; - char **paths = 0; - /* - * take order into account, directory names are used in - * alphabetical order - */ - n = 0; - for (f = label; f; f = f->next) - n++; - paths = cext_emallocz(sizeof(char *) * n); - i = 0; - for (f = label; f; f = f->next) - paths[i++] = f->name; - qsort(paths, n, sizeof(char *), comp_str); - for (i = 0; i < n; i++) { - snprintf(buf, sizeof(buf), "/%s", paths[i]); - item = cext_emallocz(sizeof(Item)); - init_item(buf, item); - cext_attach_item(&items, item); - } - free(paths); - draw(); - } -} - -static int comp_item_root(void *file, void *item) -{ - File *f = file; - Item *i = item; - - return f == i->root; -} - -static Item *get_item_for_file(File *f) -{ - return cext_find_item(&items, f, comp_item_root); -} - -static void iter_buttonpress(void *item, void *bpress) -{ - XButtonPressedEvent *e = bpress; - Item *i = item; - File *p; - char buf[MAX_BUF]; - char path[512]; - - if (blitz_ispointinrect(e->x, e->y, &i->d.rect)) { - path[0] = 0; - wmii_get_ixppath(i->root, path, sizeof(path)); - snprintf(buf, MAX_BUF, "%s/b%upress", path, e->button); - if ((p = ixp_walk(ixps, buf))) - if (p->content) - spawn(dpy, p->content); - return; - } -} - -static void handle_buttonpress(XButtonPressedEvent *e) -{ - cext_list_iterate(&items, e, iter_buttonpress); -} - -static void check_event(Connection * e) -{ - XEvent ev; - - while (XPending(dpy)) { - XNextEvent(dpy, &ev); - switch (ev.type) { - case ButtonPress: - handle_buttonpress(&ev.xbutton); - break; - case Expose: - if (ev.xexpose.count == 0) { - /* XRaiseWindow(dpy, win); */ - draw_bar(0, 0); - } - break; - default: - break; - } - } -} - -static void update_geometry() -{ - brect = rect; - brect.height = font->ascent + font->descent + 4; - if (align == SOUTH) - brect.y = rect.height - brect.height; - XMoveResizeWindow(dpy, win, brect.x, brect.y, brect.width, brect.height); - XSync(dpy, False); - XFreePixmap(dpy, pmap); - pmap = XCreatePixmap(dpy, win, brect.width, brect.height, DefaultDepth(dpy, screen_num)); - XSync(dpy, False); -} - -static void handle_after_write(IXPServer * s, File * f) -{ - int i; - size_t len; - Item *item; - char buf[512]; - - buf[0] = 0; - if (!strncmp(f->name, "data", 5)) { - if ((item = get_item_for_file(f->parent))) { - wmii_get_ixppath(f->parent, buf, sizeof(buf)); - init_draw_label(buf, &item->d); - draw(); - } - } else if (file[B_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_bar(0, 0); - } - } else if (file[B_CTL] == f) { - for (i = 0; acttbl[i].name; 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; - } - } - } else if (file[B_FONT] == f) { - XFreeFont(dpy, font); - font = blitz_getfont(dpy, file[B_FONT]->content); - update_geometry(); - draw_bar(0, 0); - } - check_event(0); -} - -static void handle_before_read(IXPServer * s, File * f) -{ - char buf[64]; - if (f == file[B_GEOMETRY]) { - if (f->content) - free(f->content); - if (align == SOUTH) - f->content = strdup("south"); - else - f->content = strdup("north"); - f->size = strlen(f->content); - } else if (f == file[B_NEW]) { - snprintf(buf, sizeof(buf), "%d", id++); - if (f->content) - free(f->content); - f->content = strdup(buf); - f->size = strlen(buf); - create_label(buf); - draw_bar(0, 0); - } -} - -static int dummy_error_handler(Display * dpy, XErrorEvent * err) -{ - return 0; -} - -int main(int argc, char *argv[]) -{ - int i; - XSetWindowAttributes wa; - XGCValues gcv; - - /* command line args */ - for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) { - switch (argv[i][1]) { - case 'v': - fprintf(stdout, "%s", version[0]); - exit(0); - break; - case 's': - if (i + 1 < argc) - sockfile = argv[++i]; - else - usage(); - break; - default: - usage(); - break; - } - } - - dpy = XOpenDisplay(0); - if (!dpy) { - fprintf(stderr, "%s", "wmibar: cannot open display\n"); - exit(1); - } - XSetErrorHandler(dummy_error_handler); - screen_num = DefaultScreen(dpy); - - ixps = wmii_setup_server(sockfile); - - - /* init */ - if (!(file[B_CTL] = ixp_create(ixps, "/ctl"))) { - perror("wmibar: cannot connect IXP server"); - exit(1); - } - file[B_CTL]->after_write = handle_after_write; - file[B_NEW] = ixp_create(ixps, "/new"); - file[B_NEW]->before_read = handle_before_read; - file[B_FONT] = wmii_create_ixpfile(ixps, "/font", BLITZ_FONT); - file[B_FONT]->after_write = handle_after_write; - font = blitz_getfont(dpy, file[B_FONT]->content); - file[B_BG_COLOR] = wmii_create_ixpfile(ixps, "/bgcolor", BLITZ_NORM_BG_COLOR); - file[B_FG_COLOR] = wmii_create_ixpfile(ixps, "/fgcolor", BLITZ_NORM_FG_COLOR); - file[B_BORDER_COLOR] = wmii_create_ixpfile(ixps, "/bordercolor", BLITZ_NORM_BORDER_COLOR); - file[B_GEOMETRY] = ixp_create(ixps, "/geometry"); - file[B_GEOMETRY]->before_read = handle_before_read; - file[B_GEOMETRY]->after_write = handle_after_write; - file[B_EXPANDABLE] = ixp_create(ixps, "/expandable"); - - wa.override_redirect = 1; - wa.background_pixmap = ParentRelative; - wa.event_mask = ExposureMask | ButtonPressMask | SubstructureRedirectMask | SubstructureNotifyMask; - - rect.x = rect.y = 0; - rect.width = DisplayWidth(dpy, screen_num); - rect.height = DisplayHeight(dpy, screen_num); - brect = rect; - brect.height = font->ascent + font->descent + 4; - brect.y = rect.height - brect.height; - - win = XCreateWindow(dpy, RootWindow(dpy, screen_num), brect.x, brect.y, - brect.width, brect.height, 0, DefaultDepth(dpy, screen_num), - CopyFromParent, DefaultVisual(dpy, screen_num), - CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); - XDefineCursor(dpy, win, XCreateFontCursor(dpy, XC_left_ptr)); - XSync(dpy, False); - - gcv.function = GXcopy; - gcv.graphics_exposures = False; - gc = XCreateGC(dpy, win, 0, 0); - - pmap = XCreatePixmap(dpy, win, brect.width, brect.height, DefaultDepth(dpy, screen_num)); - - /* main event loop */ - run_server_with_fd_support(ixps, ConnectionNumber(dpy), check_event, 0); - deinit_server(ixps); - XFreePixmap(dpy, pmap); - XFreeGC(dpy, gc); - XCloseDisplay(dpy); - - return 0; -} diff --git a/cmd/wmibar2.c b/cmd/wmibar2.c @@ -1,449 +0,0 @@ -/* - * (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ - -#include <assert.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <sys/types.h> -#include <time.h> -#include <unistd.h> -#include <X11/Xatom.h> -#include <X11/cursorfont.h> -#include <X11/Xproto.h> -#include <X11/Xutil.h> - -#include "../libixp2/ixp.h" -#include "blitz.h" - -/* - * filesystem specification - * / Droot - * /display Fdisplay 'top', 'bottom', 'none' - * /font Ffont <xlib font name> - * /new Fnew returns id of new item - * /default/ Ditem - * /default/bNpress Fevent <command, gets executed> - * /default/bgcolor Fcolor <#RRGGBB, #RGB> - * /default/fgcolor Fcolor <#RRGGBB, #RGB> - * /default/bordercolor Fcolor <#RRGGBB, #RGB> - * /1/ Ditem - * /1/data Fdata <arbitrary data which gets displayed> - * /1/bNpress Fevent <command, gets executed> - * /1/bgcolor Fcolor <#RRGGBB, #RGB> - * /1/fgcolor Fcolor <#RRGGBB, #RGB> - * /1/bordercolor Fcolor <#RRGGBB, #RGB> ... - */ -enum { /* 8-bit qid.path.type */ - Droot, - Ditem, - Fdisplay, - Fnew, - Fdata, /* data to display */ - Fevent, - Fcolor, - Ffont -}; - -#define NONE (u16)0xffff - -typedef struct { - char *name; - u8 type; -} QFile; - -static QFile qfilelist[] = { - {"display", Fdisplay}, - {"font", Ffont}, - {"new", Fnew}, - {"data", Fdata}, - {"bgcolor", Fcolor}, - {"fgcolor", Fcolor}, - {"bordercolor", Fcolor}, - {"b1press", Fevent}, - {"b2press", Fevent}, - {"b3press", Fevent}, - {"b4press", Fevent}, - {"b5press", Fevent}, - {0, 0}, -}; - -typedef struct { - u32 fid; - Qid qid; -} Map; - -typedef struct { - int id; - char text[256]; - int value; - unsigned long bg; - unsigned long fg; - unsigned long border[4]; - XFontStruct *font; - char event[5][256]; -} Item; - -static Container items = {0}; -static char *sockfile = 0; -static pid_t mypid = 0; -static IXPServer srv = { 0 }; -static Qid root_qid; -static Display *dpy; -static int screen_num; -static char *align = 0; -static char *font = 0; -/* -static GC gc; -static Window win; -static XRectangle geom; -static int mapped = 0; -static Pixmap pmap; - -static Draw zero_draw = { 0 }; -*/ - -static char *version[] = { - "wmibar - window manager improved bar - " VERSION "\n" - " (C)opyright MMIV-MMV Anselm R. Garbe\n", 0 -}; - -static void usage() -{ - fprintf(stderr, "%s %d", - "usage: wmibar -s <socket file> [-v]\n" - " -s socket file\n" " -v version info\n", - NONE); - exit(1); -} - -static int dummy_error_handler(Display * dpy, XErrorEvent * err) -{ - return 0; -} - -static void exit_cleanup() -{ - if (mypid == getpid()) - unlink(sockfile); -} - -static u64 make_qpath(u8 type, u16 item, u16 file) -{ - return ((u64) file << 24) | ((u64) item << 8) | (u64) type; -} - -static u8 qpath_type(u64 path) -{ - return path & 0xff; -} - -static u16 qpath_item(u64 path) -{ - return (path >> 8) & 0xffff; -} - -/* -static u16 -qpath_file(u64 path) -{ - return (path >> 24) & 0xffff; -} -*/ - -static int comp_fid(void *fid, void *map) -{ - return ((Map *)map)->fid == *(u32 *)fid; -} - -static Map *fid_to_map(Container *maps, u32 fid) -{ - return cext_find_item(maps, &fid, comp_fid); -} - -static Bool qfile_index(char *name, u16 * index) -{ - int i; - for (i = 0; qfilelist[i].name; i++) - if (!strncmp(name, qfilelist[i].name, strlen(qfilelist[i].name))) { - *index = i; - return True; - } - return False; -} - -static Bool make_qid(Qid * dir, char *wname, Qid * new) -{ - u16 idx; - const char *errstr; - if (dir->type != IXP_QTDIR) - return False; - new->version = 0; - if (!qfile_index(wname, &idx)) { - new->type = IXP_QTDIR; - if (!strncmp(wname, "..", 3)) { - *new = root_qid; - return True; - } else if (!strncmp(wname, "default", 8)) { - new->path = make_qpath(Ditem, 0, NONE); - return True; - } - /* check if wname is a number, otherwise file not found */ - idx = (u16) cext_strtonum(wname, 1, 0xffff, &errstr); - if (errstr || cext_sizeof(&items) < idx) - return False; - /* found */ - new->path = make_qpath(Ditem, idx, NONE); - } else { - new->type = IXP_QTFILE; - new->path = make_qpath(qfilelist[idx].type, qpath_item(dir->path), idx); - } - return True; -} - -static int attach(IXPServer *s, IXPConn *c) -{ - Container *cont = c->aux; - Map *map = cext_emallocz(sizeof(Map)); - - if (!cont) - cont = c->aux = cext_emallocz(sizeof(Container)); - fprintf(stderr, "attaching %d %s %s\n", s->fcall.afid, s->fcall.uname, s->fcall.aname); - map->qid = root_qid; - map->fid = s->fcall.fid; - cext_attach_item(cont, map); - s->fcall.id = RATTACH; - s->fcall.qid = root_qid; - return TRUE; -} - -static int walk(IXPServer * s, IXPConn * c) -{ - u16 nwqid = 0; - Qid qid; - Map *map; - - fprintf(stderr, "%s", "walking\n"); - if (!(map = fid_to_map(c->aux, s->fcall.fid))) { - s->errstr = "no directory associated with fid"; - return FALSE; - } - if (s->fcall.fid != s->fcall.newfid - && (fid_to_map(c->aux, s->fcall.newfid))) { - s->errstr = "fid alreay in use"; - return FALSE; - } - if (s->fcall.nwname) { - qid = map->qid; - for (nwqid = 0; (nwqid < s->fcall.nwname) && make_qid(&qid, s->fcall.wname[nwqid], &s->fcall.wqid[nwqid]); nwqid++) - qid = s->fcall.wqid[nwqid]; - if (!nwqid) { - s->errstr = "file not found"; - return FALSE; - } - } - /* - * following condition is required by 9P, a fid will only be valid if - * the walk was complete - */ - if (nwqid == s->fcall.nwname) { - Container *cont = c->aux; - if (s->fcall.fid == s->fcall.newfid) { - cext_detach_item(cont, map); - free(map); - } - map = cext_emallocz(sizeof(Map)); - map->qid = qid; - map->fid = s->fcall.newfid; - cext_attach_item(cont, map); - } - s->fcall.id = RWALK; - s->fcall.nwqid = nwqid; - return TRUE; -} - -static int _open(IXPServer * s, IXPConn * c) -{ - Map *map = fid_to_map(c->aux, s->fcall.fid); - - fprintf(stderr, "%s", "opening\n"); - if (!map) { - s->errstr = "invalid fid"; - return FALSE; - } - if ((s->fcall.mode != IXP_OREAD) && (s->fcall.mode != IXP_OWRITE)) { - s->errstr = "mode not supported"; - return FALSE; - } - s->fcall.id = ROPEN; - s->fcall.qid = map->qid; - s->fcall.iounit = - s->fcall.maxmsg - (sizeof(u8) + sizeof(u16) + 2 * sizeof(u32)); - return TRUE; -} - -static int _read(IXPServer * s, IXPConn * c) -{ - Map *map = fid_to_map(c->aux, s->fcall.fid); - Stat stat = { 0 }; - u8 *p; - - fprintf(stderr, "%s", "reading\n"); - if (!map) { - s->errstr = "invalid fid"; - return FALSE; - } - stat.mode = 0xff; - stat.atime = stat.mtime = time(0); - cext_strlcpy(stat.uid, getenv("USER"), sizeof(stat.uid)); - cext_strlcpy(stat.gid, getenv("USER"), sizeof(stat.gid)); - cext_strlcpy(stat.muid, getenv("USER"), sizeof(stat.muid)); - - fprintf(stderr, "%d\n", qpath_item(map->qid.path)); - switch (qpath_type(map->qid.path)) { - default: - case Droot: - p = s->fcall.data; - cext_strlcpy(stat.name, "display", sizeof(stat.name)); - stat.length = strlen(align); - make_qid(&root_qid, "display", &stat.qid); - stat.size = ixp_sizeof_stat(&stat); - s->fcall.count = stat.size; - p = ixp_enc_stat(p, &stat); - cext_strlcpy(stat.name, "font", sizeof(stat.name)); - stat.length = strlen(font); - make_qid(&root_qid, "font", &stat.qid); - stat.size = ixp_sizeof_stat(&stat);; - s->fcall.count += stat.size; - p = ixp_enc_stat(p, &stat); - cext_strlcpy(stat.name, "new", sizeof(stat.name)); - stat.length = 0; - make_qid(&root_qid, "new", &stat.qid); - stat.size = ixp_sizeof_stat(&stat);; - s->fcall.count += stat.size; - p = ixp_enc_stat(p, &stat); - s->fcall.id = RREAD; - fprintf(stderr, "%d msize\n", s->fcall.count); - break; - case Ditem: - break; - case Fdisplay: - break; - case Fnew: - break; - case Fdata: - break; - case Fevent: - break; - case Fcolor: - break; - case Ffont: - break; - } - - return TRUE; -} - -static int _write(IXPServer *s, IXPConn *c) -{ - - return FALSE; -} - -static int clunk(IXPServer *s, IXPConn *c) -{ - Container *cont = c->aux; - Map *map = fid_to_map(cont, s->fcall.fid); - - if (!map) { - s->errstr = "invalid fid"; - return FALSE; - } - cext_detach_item(cont, map); - free(map); - s->fcall.id = RCLUNK; - return TRUE; -} - -static void freeconn(IXPServer * s, IXPConn * c) -{ - Container *cont = c->aux; - if (cont) { - free(cont); - c->aux = 0; - } -} - -static IXPTFunc funcs[] = { - {TVERSION, ixp_server_tversion}, - {TATTACH, attach}, - {TWALK, walk}, - {TOPEN, _open}, - {TREAD, _read}, - {TWRITE, _write}, - {TCLUNK, clunk}, - {0, 0} -}; - -int main(int argc, char *argv[]) -{ - int i; - Item *item; - - /* command line args */ - for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) { - switch (argv[i][1]) { - case 'v': - fprintf(stdout, "%s", version[0]); - exit(0); - break; - case 's': - if (i + 1 < argc) - sockfile = argv[++i]; - else - usage(); - break; - default: - usage(); - break; - } - } - - dpy = XOpenDisplay(0); - if (!dpy) { - fprintf(stderr, "%s", "wmibar: cannot open display\n"); - exit(1); - } - XSetErrorHandler(dummy_error_handler); - screen_num = DefaultScreen(dpy); - - if (!ixp_server_init(&srv, sockfile, funcs, freeconn)) { - fprintf(stderr, "wmibar: fatal: %s\n", srv.errstr); - exit(1); - } - root_qid.type = IXP_QTDIR; - root_qid.version = 0; - root_qid.path = make_qpath(Droot, NONE, NONE); - - mypid = getpid(); - atexit(exit_cleanup); - - /* default item settings */ - item = cext_emallocz(sizeof(Item)); - - align = "bottom"; - font = "fixed"; - - ixp_server_loop(&srv); - if (srv.errstr) { - fprintf(stderr, "wmibar: fatal: %s\n", srv.errstr); - ixp_server_deinit(&srv); - exit(1); - } - ixp_server_deinit(&srv); - return 0; -} diff --git a/cmd/wmifs.1 b/cmd/wmifs.1 @@ -1,38 +0,0 @@ -.TH WMIFS 1 wmii-3 -.SH NAME -wmifs \- window manager improved 2 filesystem -.SH SYNOPSIS -.B wmifs -.B \-s -.I socketfile -.SH DESCRIPTION -.SS Overview -.B wmifs -is a socket-based fileserver which is used for binding other fileserver -filesystems to a specific namespace. It routes filesystem accesses to -the specific fileserver and behaves to the outside as one master -filesystem. -.SS Options -.TP -.BI \-s " socketfile" -specifies the socketfile that -.B wmifs -should create. -.TP -.B \-v -prints version information to stderr, then exits. -.SS Customization -.B wmifs -is customized through manipulating its filesystem namespace. -In the default setup of -.BR wmii (1) -the namespace of -.B wmifs -can be found in /. -.SH SEE ALSO -.BR wmibar (1), -.BR wmii (1), -.BR wmiiwm (1), -.BR wmikeys (1), -.BR wmimenu (1), -.BR wmir (1) diff --git a/cmd/wmifs.c b/cmd/wmifs.c @@ -1,376 +0,0 @@ -/* - * (C)opyright MMV Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "wmii.h" - -/* array indexes for file pointers */ -typedef enum { - F_CTL, - F_LAST -} FsIndexes; - -typedef struct Route Route; -struct Route { - File dest; - int src; -}; - -typedef struct Bind Bind; -struct Bind { - IXPClient *client; - Route route[MAX_CONN * MAX_OPEN_FILES]; - File *mount; - char *prefix; -}; - -static Display *dpy; -static IXPServer *ixps; -static char *sockfile = 0; -static File *files[F_LAST]; -static Container bindings = {0}; - -static void quit(void *obj, char *arg); -static void bind(void *obj, char *arg); -static void unbind(void *obj, char *arg); - -static Action acttbl[] = { - {"quit", quit}, - {"unbind", unbind}, - {"bind", bind}, - {0, 0} -}; - -static char *version[] = { - "wmifs - window manager improved filesystem - " VERSION "\n" - " (C)opyright MMV Anselm R. Garbe\n", 0 -}; - -static void usage() -{ - fprintf(stderr, - "usage: wmifs -s <socket file> [-v]\n" - " -s socket file\n" " -v version info\n"); - exit(1); -} - -static void iter_unbind(void *bind, void *aux) -{ - Bind *b = bind; - if (b->mount) { - b->mount->content = 0; - ixp_remove(ixps, b->prefix); - if (ixps->errstr) - fprintf(stderr, "wmifs: error on unbind %s: %s\n", b->prefix, ixps->errstr); - } -} - -static void quit(void *obj, char *arg) -{ - cext_list_iterate(&bindings, nil, iter_unbind); - ixps->runlevel = SHUTDOWN; -} - -static void do_unbind(Bind * b) -{ - cext_detach_item(&bindings, b); - iter_unbind(b, nil); - /* free stuff */ - deinit_client(b->client); - free(b->prefix); - free(b); -} - -static int comp_bindpath(void *path, void *bind) -{ - Bind *b = bind; - return !strncmp(b->prefix, path, strlen(b->prefix)); -} - -static void unbind(void *obj, char *arg) -{ - Bind *b = cext_find_item(&bindings, arg, comp_bindpath); - - if (!b) { - fprintf(stderr, "wmifs: unbind: '%s' no such path\n", arg); - return; - } - do_unbind(b); -} - -static void bind(void *obj, char *arg) -{ - Bind *b = 0; - char cmd[1024]; - char *sfile; - - if (!arg) - return; - cext_strlcpy(cmd, arg, sizeof(cmd)); - sfile = strchr(cmd, ' '); - if (!sfile) { - fprintf(stderr, "wmifs: bind: '%s' without socket argument, ignoring\n", arg); - return; /* shortcut with empty argument */ - } - *sfile = 0; - sfile++; - if (*sfile == 0) { - fprintf(stderr, "wmifs: bind: '%s' without socket argument, ignoring\n", arg); - return; /* shortcut with empty argument */ - } - b = cext_emallocz(sizeof(Bind)); - b->client = init_ixp_client(sfile); - - if (!b->client) { - fprintf(stderr, "wmifs: bind: cannot connect to server '%s', ignoring\n", sfile); - free(b); - return; - } - b->prefix = strdup(cmd); - b->mount = ixp_create(ixps, b->prefix); - b->mount->content = b->mount; /* shall be a directory */ - - cext_attach_item(&bindings, b); -} - -static void handle_after_write(IXPServer * s, File * f) -{ - int i; - size_t len; - - for (i = 0; acttbl[i].name; 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; - } - } -} - -static Bind *fd_to_bind(int fd, int *client_fd) -{ - File *f = fd_to_file(ixps, fd); - unsigned int i, j; - Bind *b; - size_t size = cext_sizeof(&bindings); - - if (!f) - return nil; - for (i = 0; i < size; i++) { - b = cext_list_get_item(&bindings, i); - for (j = 0; j < MAX_CONN * MAX_OPEN_FILES; j++) { - if (&b->route[j].dest == f) { - *client_fd = b->route[j].src; - return b; - } - } - } - return nil; -} - -static File *fixp_create(IXPServer * s, char *path) -{ - Bind *b = cext_find_item(&bindings, path, comp_bindpath); - size_t len; - - if (!b) { - File *f = ixp_create(s, path); - return f; - } - /* route to b */ - len = strlen(b->prefix); - b->client->create(b->client, path[len] == 0 ? "/" : &path[len]); - if (b->client->errstr) { - if (!strcmp(b->client->errstr, DEAD_SERVER)) - do_unbind(b); - } - return nil; -} - -static File *fixp_open(IXPServer * s, char *path) -{ - Bind *b = cext_find_item(&bindings, path, comp_bindpath); - int fd; - size_t len; - - if (!b) { - File *f = ixp_open(s, path); - return f; - } - /* route to b */ - len = strlen(b->prefix); - fd = b->client->open(b->client, path[len] == 0 ? "/" : &path[len]); - if (b->client->errstr) { - set_error(s, b->client->errstr); - if (!strcmp(b->client->errstr, DEAD_SERVER)) - do_unbind(b); - return nil; - } - b->route[fd].src = fd; - return &b->route[fd].dest; -} - -static size_t -fixp_read(IXPServer * s, int fd, size_t offset, void *out_buf, - size_t out_buf_len) -{ - int cfd; - Bind *b = fd_to_bind(fd, &cfd); - size_t result; - - if (!b) { - result = ixp_read(s, fd, offset, out_buf, out_buf_len); - return result; - } - /* route to b */ - result = seek_read(b->client, cfd, offset, out_buf, out_buf_len); - if (b->client->errstr) { - set_error(s, b->client->errstr); - if (!strcmp(b->client->errstr, DEAD_SERVER)) - do_unbind(b); - } - return result; -} - -static void -fixp_write(IXPServer * s, int fd, size_t offset, void *content, - size_t in_len) -{ - int cfd; - Bind *b = fd_to_bind(fd, &cfd); - - if (!b) { - ixp_write(s, fd, offset, content, in_len); - return; - } - /* route to b */ - seek_write(b->client, cfd, offset, content, in_len); - if (b->client->errstr) { - set_error(s, b->client->errstr); - if (!strcmp(b->client->errstr, DEAD_SERVER)) - do_unbind(b); - } -} - -static void fixp_close(IXPServer * s, int fd) -{ - int cfd; - Bind *b = fd_to_bind(fd, &cfd); - - if (!b) { - ixp_close(s, fd); - return; - } - /* route to b */ - b->client->close(b->client, cfd); - if (b->client->errstr) { - set_error(s, b->client->errstr); - if (!strcmp(b->client->errstr, DEAD_SERVER)) - do_unbind(b); - } -} - -static void fixp_remove(IXPServer * s, char *path) -{ - Bind *b = cext_find_item(&bindings, path, comp_bindpath); - size_t len; - - if (!b) { - ixp_remove(s, path); - return; - } - /* route to b */ - len = strlen(b->prefix); - b->client->remove(b->client, path[len] == 0 ? "/" : &path[len]); - if (b->client->errstr) { - set_error(s, b->client->errstr); - if (!strcmp(b->client->errstr, DEAD_SERVER)) - do_unbind(b); - } -} - -static void check_event(Connection * e) -{ - XEvent ev; - while (XPending(dpy)) { - /* - * wmifs isn't interested in any X events, so just drop them - * all - */ - XNextEvent(dpy, &ev); - } - /* why check them? because X won't kill wmifs when X dies */ -} - -static void run() -{ - if (!(files[F_CTL] = ixp_create(ixps, "/ctl"))) { - perror("wmifs: cannot connect IXP server"); - exit(1); - } - files[F_CTL]->after_write = handle_after_write; - - /* routing functions */ - ixps->create = fixp_create; - ixps->remove = fixp_remove; - ixps->open = fixp_open; - ixps->close = fixp_close; - ixps->read = fixp_read; - ixps->write = fixp_write; - - /* main event loop */ - run_server_with_fd_support(ixps, ConnectionNumber(dpy), - check_event, 0); - - deinit_server(ixps); -} - -int main(int argc, char *argv[]) -{ - int i; - - /* command line args */ - for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) { - switch (argv[i][1]) { - case 'v': - fprintf(stdout, "%s", version[0]); - exit(0); - break; - case 's': - if (i + 1 < argc) - sockfile = argv[++i]; - else - usage(); - break; - default: - usage(); - break; - } - } - - if (!getenv("HOME")) { - fprintf(stderr, "%s", - "wmifs: $HOME environment variable is not set\n"); - usage(); - } - /* just for the case X crashes/gets quit */ - dpy = XOpenDisplay(0); - if (!dpy) { - fprintf(stderr, "%s", "wmifs: cannot open display\n"); - exit(1); - } - ixps = wmii_setup_server(sockfile); - - run(); - - return 0; -} diff --git a/cmd/wmiibar.1 b/cmd/wmiibar.1 @@ -0,0 +1,43 @@ +.TH WMIBAR 1 wmii-3 +.SH NAME +wmibar \- window manager improved 2 bar +.SH SYNOPSIS +.B wmibar +.B \-s +.I socketfile +.SH DESCRIPTION +.SS Overview +.B wmibar +is a generic and highly customizable bar for the X Window System, +originally designed for +.BR wmii (1). +It supports arbitrary sized labels with arbitrary styles on a per label +basis and with button click events. +Like wmii, +.B wmibar +also implements a socket-based fileserver, which is accessed to configure and +interoperate with other components. +.SS Options +.TP +.BI \-s " socketfile" +specifies the socketfile that +.B wmibar +should create. +.TP +.B \-v +prints version information to stderr, then exits. +.SS Customization +.B wmibar +is customized through manipulating its filesystem namespace. +In the default setup of +.BR wmii (1) +the namespace of +.B wmibar +can be found in /bar. +.SH SEE ALSO +.BR wmifs (1), +.BR wmii (1), +.BR wmiiwm (1), +.BR wmikeys (1), +.BR wmimenu (1), +.BR wmir (1) diff --git a/cmd/wmiibar.c b/cmd/wmiibar.c @@ -0,0 +1,534 @@ +/* + * (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com> + * See LICENSE file for license details. + */ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <X11/Xatom.h> +#include <X11/cursorfont.h> +#include <X11/Xproto.h> +#include <X11/Xutil.h> + +#include "wmii.h" + +/* array indexes for file pointers */ +typedef enum { + B_CTL, + B_NEW, + B_EXPANDABLE, + B_GEOMETRY, + B_FONT, + B_FG_COLOR, + B_BORDER_COLOR, + B_BG_COLOR, + B_LAST +} BarIndexes; + +typedef struct { + File *root; + Draw d; +} Item; + +static unsigned int id = 0; +static IXPServer *ixps = 0; +static Display *dpy; +static GC gc; +static Window win; +static XRectangle rect; +static XRectangle brect; +static int screen_num; +static int displayed = 0; +static char *sockfile = 0; +static File *file[B_LAST]; +static Container items = {0}; +static Pixmap pmap; +static XFontStruct *font; +static Align align = SOUTH; + +static Draw zero_draw = { 0 }; + +static void draw_bar(void *obj, char *arg); +static void quit(void *obj, char *arg); +static void display(void *obj, char *arg); +static void reset(void *obj, char *arg); +static void _destroy(void *obj, char *arg); +static void handle_after_write(IXPServer * s, File * f); + +static Action acttbl[] = { + {"quit", quit}, + {"display", display}, + {"update", draw_bar}, + {"reset", reset}, + {"destroy", _destroy}, + {0, 0} +}; + +static char *version[] = { + "wmibar - window manager improved bar - " VERSION "\n" + " (C)opyright MMIV-MMV Anselm R. Garbe\n", 0 +}; + +static void usage() +{ + fprintf(stderr, "%s", + "usage: wmibar -s <socket file> [-v]\n" + " -s socket file\n" " -v version info\n"); + exit(1); +} + +/** + * <path>/data "<txt value>" + * <path>/fgcolor "#RRGGBBAA" + * <path>/bgcolor "#RRGGBBAA" + * <path>/bordercolor "#RRGGBBAA" + * <path>/b1press "<command>" + * <path>/b2press "<command>" + * <path>/b3press "<command>" + * <path>/b4press "<command>" + * <path>/b5press "<command>" + */ +static void create_label(char *path) +{ + File *f; + char buf[MAX_BUF]; + int i; + + snprintf(buf, MAX_BUF, "%s/data", path); + f = ixp_create(ixps, buf); + f->after_write = handle_after_write; + snprintf(buf, MAX_BUF, "%s/fgcolor", path); + wmii_create_ixpfile(ixps, buf, file[B_FG_COLOR]->content); + snprintf(buf, MAX_BUF, "%s/bgcolor", path); + wmii_create_ixpfile(ixps, buf, file[B_BG_COLOR]->content); + snprintf(buf, MAX_BUF, "%s/bordercolor", path); + wmii_create_ixpfile(ixps, buf, file[B_BORDER_COLOR]->content); + for (i = 1; i < 6; i++) { /* 5 buttons events */ + snprintf(buf, MAX_BUF, "%s/b%dpress", path, i); + ixp_create(ixps, buf); + } +} + +static void _destroy(void *obj, char *arg) +{ + char buf[512]; + if (!arg) + return; + snprintf(buf, sizeof(buf), "/%s", arg); + ixps->remove(ixps, buf); + draw_bar(0, 0); +} + +static void reset(void *obj, char *arg) +{ + int i; + char buf[512]; + for (i = 0; i < id; i++) { + snprintf(buf, sizeof(buf), "/%d", i); + ixps->remove(ixps, buf); + } + id = 0; + draw_bar(0, 0); +} + +static void quit(void *obj, char *arg) +{ + ixps->runlevel = SHUTDOWN; +} + +static void display(void *obj, char *arg) +{ + if (!arg) + return; + displayed = blitz_strtonum(arg, 0, 1); + if (displayed) { + XMapRaised(dpy, win); + draw_bar(0, 0); + } else { + XUnmapWindow(dpy, win); + XSync(dpy, False); + } +} + +static void init_draw_label(char *path, Draw *d) +{ + char buf[MAX_BUF]; + File *f; + + /* text stuff */ + snprintf(buf, MAX_BUF, "%s/data", path); + f = ixp_walk(ixps, buf); + d->data = f->content; + /* style stuff */ + snprintf(buf, MAX_BUF, "%s/fgcolor", path); + f = ixp_walk(ixps, buf); + d->fg = blitz_loadcolor(dpy, screen_num, f->content); + snprintf(buf, MAX_BUF, "%s/bgcolor", path); + f = ixp_walk(ixps, buf); + d->bg = blitz_loadcolor(dpy, screen_num, f->content); + snprintf(buf, MAX_BUF, "%s/bordercolor", path); + f = ixp_walk(ixps, buf); + d->border = blitz_loadcolor(dpy, screen_num, f->content); +} + +static void init_item(char *path, Item *i) +{ + i->d = zero_draw; + i->root = ixp_walk(ixps, path); + i->d.gc = gc; + i->d.drawable = pmap; + i->d.rect = brect; + i->d.rect.y = 0; + init_draw_label(path, &i->d); +} + +static int comp_str(const void *s1, const void *s2) +{ + return strcmp(*(char **) s1, *(char **) s2); +} + +static void draw() +{ + Item *item; + unsigned int i, w, xoff = 0; + unsigned expandable = 0; + char buf[32]; + size_t size = cext_sizeof(&items); + + if (!size) + return; + + expandable = blitz_strtonum(file[B_EXPANDABLE]->content, 0, size); + snprintf(buf, sizeof(buf), "/%d", expandable); + if (!ixp_walk(ixps, buf)) + expandable = 0; + + w = 0; + /* precalc */ + for (i = 0; i < size; i++) + if (i != expandable) { + item = cext_list_get_item(&items, i); + item->d.rect.width = brect.height; + if (item->d.data) { + if (!strncmp(item->d.data, "%m:", 3)) + /* meter */ + item->d.rect.width = brect.height / 2; + else + item->d.rect.width += XTextWidth(font, item->d.data, strlen(item->d.data)); + } + w += item->d.rect.width; + } + if (w > brect.width) { + /* failsafe mode, give all labels same width */ + w = brect.width / size; + for (i = 0; i < size; i++) { + item = cext_list_get_item(&items, i); + item->d.rect.width = w; + } + item->d.rect.width = brect.width - item->d.rect.x; + } + else { + item = cext_list_get_item(&items, expandable); + item->d.rect.width = brect.width - w; + } + for (i = 0; i < size; i++) { + item = cext_list_get_item(&items, i); + item->d.font = font; + item->d.rect.x = xoff; + xoff += item->d.rect.width; + if (item->d.data && !strncmp(item->d.data, "%m:", 3)) + blitz_drawmeter(dpy, &item->d); + else + blitz_drawlabel(dpy, &item->d); + } + XCopyArea(dpy, pmap, win, gc, 0, 0, brect.width, brect.height, 0, 0); + XSync(dpy, False); +} + +static void draw_bar(void *obj, char *arg) +{ + File *label = 0; + unsigned int i = 0, n = 0; + Item *item; + char buf[512]; + + if (!displayed) + return; + while ((item = cext_stack_get_top_item(&items))) { + cext_detach_item(&items, item); + free(item); + } + snprintf(buf, sizeof(buf), "%s", "/0"); + label = ixp_walk(ixps, buf); + if (!label) { + Draw d = { 0 }; + /* default stuff */ + d.gc = gc; + d.drawable = pmap; + d.rect.width = brect.width; + d.rect.height = brect.height; + d.bg = blitz_loadcolor(dpy, screen_num, file[B_BG_COLOR]->content); + d.fg = blitz_loadcolor(dpy, screen_num, file[B_FG_COLOR]->content); + d.border = blitz_loadcolor(dpy, screen_num, file[B_BORDER_COLOR]->content); + blitz_drawlabelnoborder(dpy, &d); + } else { + File *f; + char **paths = 0; + /* + * take order into account, directory names are used in + * alphabetical order + */ + n = 0; + for (f = label; f; f = f->next) + n++; + paths = cext_emallocz(sizeof(char *) * n); + i = 0; + for (f = label; f; f = f->next) + paths[i++] = f->name; + qsort(paths, n, sizeof(char *), comp_str); + for (i = 0; i < n; i++) { + snprintf(buf, sizeof(buf), "/%s", paths[i]); + item = cext_emallocz(sizeof(Item)); + init_item(buf, item); + cext_attach_item(&items, item); + } + free(paths); + draw(); + } +} + +static int comp_item_root(void *file, void *item) +{ + File *f = file; + Item *i = item; + + return f == i->root; +} + +static Item *get_item_for_file(File *f) +{ + return cext_find_item(&items, f, comp_item_root); +} + +static void iter_buttonpress(void *item, void *bpress) +{ + XButtonPressedEvent *e = bpress; + Item *i = item; + File *p; + char buf[MAX_BUF]; + char path[512]; + + if (blitz_ispointinrect(e->x, e->y, &i->d.rect)) { + path[0] = 0; + wmii_get_ixppath(i->root, path, sizeof(path)); + snprintf(buf, MAX_BUF, "%s/b%upress", path, e->button); + if ((p = ixp_walk(ixps, buf))) + if (p->content) + spawn(dpy, p->content); + return; + } +} + +static void handle_buttonpress(XButtonPressedEvent *e) +{ + cext_list_iterate(&items, e, iter_buttonpress); +} + +static void check_event(Connection * e) +{ + XEvent ev; + + while (XPending(dpy)) { + XNextEvent(dpy, &ev); + switch (ev.type) { + case ButtonPress: + handle_buttonpress(&ev.xbutton); + break; + case Expose: + if (ev.xexpose.count == 0) { + /* XRaiseWindow(dpy, win); */ + draw_bar(0, 0); + } + break; + default: + break; + } + } +} + +static void update_geometry() +{ + brect = rect; + brect.height = font->ascent + font->descent + 4; + if (align == SOUTH) + brect.y = rect.height - brect.height; + XMoveResizeWindow(dpy, win, brect.x, brect.y, brect.width, brect.height); + XSync(dpy, False); + XFreePixmap(dpy, pmap); + pmap = XCreatePixmap(dpy, win, brect.width, brect.height, DefaultDepth(dpy, screen_num)); + XSync(dpy, False); +} + +static void handle_after_write(IXPServer * s, File * f) +{ + int i; + size_t len; + Item *item; + char buf[512]; + + buf[0] = 0; + if (!strncmp(f->name, "data", 5)) { + if ((item = get_item_for_file(f->parent))) { + wmii_get_ixppath(f->parent, buf, sizeof(buf)); + init_draw_label(buf, &item->d); + draw(); + } + } else if (file[B_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_bar(0, 0); + } + } else if (file[B_CTL] == f) { + for (i = 0; acttbl[i].name; 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; + } + } + } else if (file[B_FONT] == f) { + XFreeFont(dpy, font); + font = blitz_getfont(dpy, file[B_FONT]->content); + update_geometry(); + draw_bar(0, 0); + } + check_event(0); +} + +static void handle_before_read(IXPServer * s, File * f) +{ + char buf[64]; + if (f == file[B_GEOMETRY]) { + if (f->content) + free(f->content); + if (align == SOUTH) + f->content = strdup("south"); + else + f->content = strdup("north"); + f->size = strlen(f->content); + } else if (f == file[B_NEW]) { + snprintf(buf, sizeof(buf), "%d", id++); + if (f->content) + free(f->content); + f->content = strdup(buf); + f->size = strlen(buf); + create_label(buf); + draw_bar(0, 0); + } +} + +static int dummy_error_handler(Display * dpy, XErrorEvent * err) +{ + return 0; +} + +int main(int argc, char *argv[]) +{ + int i; + XSetWindowAttributes wa; + XGCValues gcv; + + /* command line args */ + for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) { + switch (argv[i][1]) { + case 'v': + fprintf(stdout, "%s", version[0]); + exit(0); + break; + case 's': + if (i + 1 < argc) + sockfile = argv[++i]; + else + usage(); + break; + default: + usage(); + break; + } + } + + dpy = XOpenDisplay(0); + if (!dpy) { + fprintf(stderr, "%s", "wmibar: cannot open display\n"); + exit(1); + } + XSetErrorHandler(dummy_error_handler); + screen_num = DefaultScreen(dpy); + + ixps = wmii_setup_server(sockfile); + + + /* init */ + if (!(file[B_CTL] = ixp_create(ixps, "/ctl"))) { + perror("wmibar: cannot connect IXP server"); + exit(1); + } + file[B_CTL]->after_write = handle_after_write; + file[B_NEW] = ixp_create(ixps, "/new"); + file[B_NEW]->before_read = handle_before_read; + file[B_FONT] = wmii_create_ixpfile(ixps, "/font", BLITZ_FONT); + file[B_FONT]->after_write = handle_after_write; + font = blitz_getfont(dpy, file[B_FONT]->content); + file[B_BG_COLOR] = wmii_create_ixpfile(ixps, "/bgcolor", BLITZ_NORM_BG_COLOR); + file[B_FG_COLOR] = wmii_create_ixpfile(ixps, "/fgcolor", BLITZ_NORM_FG_COLOR); + file[B_BORDER_COLOR] = wmii_create_ixpfile(ixps, "/bordercolor", BLITZ_NORM_BORDER_COLOR); + file[B_GEOMETRY] = ixp_create(ixps, "/geometry"); + file[B_GEOMETRY]->before_read = handle_before_read; + file[B_GEOMETRY]->after_write = handle_after_write; + file[B_EXPANDABLE] = ixp_create(ixps, "/expandable"); + + wa.override_redirect = 1; + wa.background_pixmap = ParentRelative; + wa.event_mask = ExposureMask | ButtonPressMask | SubstructureRedirectMask | SubstructureNotifyMask; + + rect.x = rect.y = 0; + rect.width = DisplayWidth(dpy, screen_num); + rect.height = DisplayHeight(dpy, screen_num); + brect = rect; + brect.height = font->ascent + font->descent + 4; + brect.y = rect.height - brect.height; + + win = XCreateWindow(dpy, RootWindow(dpy, screen_num), brect.x, brect.y, + brect.width, brect.height, 0, DefaultDepth(dpy, screen_num), + CopyFromParent, DefaultVisual(dpy, screen_num), + CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); + XDefineCursor(dpy, win, XCreateFontCursor(dpy, XC_left_ptr)); + XSync(dpy, False); + + gcv.function = GXcopy; + gcv.graphics_exposures = False; + gc = XCreateGC(dpy, win, 0, 0); + + pmap = XCreatePixmap(dpy, win, brect.width, brect.height, DefaultDepth(dpy, screen_num)); + + /* main event loop */ + run_server_with_fd_support(ixps, ConnectionNumber(dpy), check_event, 0); + deinit_server(ixps); + XFreePixmap(dpy, pmap); + XFreeGC(dpy, gc); + XCloseDisplay(dpy); + + return 0; +} diff --git a/cmd/wmiibar2.c b/cmd/wmiibar2.c @@ -0,0 +1,449 @@ +/* + * (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com> + * See LICENSE file for license details. + */ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> +#include <X11/Xatom.h> +#include <X11/cursorfont.h> +#include <X11/Xproto.h> +#include <X11/Xutil.h> + +#include "../libixp2/ixp.h" +#include "blitz.h" + +/* + * filesystem specification + * / Droot + * /display Fdisplay 'top', 'bottom', 'none' + * /font Ffont <xlib font name> + * /new Fnew returns id of new item + * /default/ Ditem + * /default/bNpress Fevent <command, gets executed> + * /default/bgcolor Fcolor <#RRGGBB, #RGB> + * /default/fgcolor Fcolor <#RRGGBB, #RGB> + * /default/bordercolor Fcolor <#RRGGBB, #RGB> + * /1/ Ditem + * /1/data Fdata <arbitrary data which gets displayed> + * /1/bNpress Fevent <command, gets executed> + * /1/bgcolor Fcolor <#RRGGBB, #RGB> + * /1/fgcolor Fcolor <#RRGGBB, #RGB> + * /1/bordercolor Fcolor <#RRGGBB, #RGB> ... + */ +enum { /* 8-bit qid.path.type */ + Droot, + Ditem, + Fdisplay, + Fnew, + Fdata, /* data to display */ + Fevent, + Fcolor, + Ffont +}; + +#define NONE (u16)0xffff + +typedef struct { + char *name; + u8 type; +} QFile; + +static QFile qfilelist[] = { + {"display", Fdisplay}, + {"font", Ffont}, + {"new", Fnew}, + {"data", Fdata}, + {"bgcolor", Fcolor}, + {"fgcolor", Fcolor}, + {"bordercolor", Fcolor}, + {"b1press", Fevent}, + {"b2press", Fevent}, + {"b3press", Fevent}, + {"b4press", Fevent}, + {"b5press", Fevent}, + {0, 0}, +}; + +typedef struct { + u32 fid; + Qid qid; +} Map; + +typedef struct { + int id; + char text[256]; + int value; + unsigned long bg; + unsigned long fg; + unsigned long border[4]; + XFontStruct *font; + char event[5][256]; +} Item; + +static Container items = {0}; +static char *sockfile = 0; +static pid_t mypid = 0; +static IXPServer srv = { 0 }; +static Qid root_qid; +static Display *dpy; +static int screen_num; +static char *align = 0; +static char *font = 0; +/* +static GC gc; +static Window win; +static XRectangle geom; +static int mapped = 0; +static Pixmap pmap; + +static Draw zero_draw = { 0 }; +*/ + +static char *version[] = { + "wmibar - window manager improved bar - " VERSION "\n" + " (C)opyright MMIV-MMV Anselm R. Garbe\n", 0 +}; + +static void usage() +{ + fprintf(stderr, "%s %d", + "usage: wmibar -s <socket file> [-v]\n" + " -s socket file\n" " -v version info\n", + NONE); + exit(1); +} + +static int dummy_error_handler(Display * dpy, XErrorEvent * err) +{ + return 0; +} + +static void exit_cleanup() +{ + if (mypid == getpid()) + unlink(sockfile); +} + +static u64 make_qpath(u8 type, u16 item, u16 file) +{ + return ((u64) file << 24) | ((u64) item << 8) | (u64) type; +} + +static u8 qpath_type(u64 path) +{ + return path & 0xff; +} + +static u16 qpath_item(u64 path) +{ + return (path >> 8) & 0xffff; +} + +/* +static u16 +qpath_file(u64 path) +{ + return (path >> 24) & 0xffff; +} +*/ + +static int comp_fid(void *fid, void *map) +{ + return ((Map *)map)->fid == *(u32 *)fid; +} + +static Map *fid_to_map(Container *maps, u32 fid) +{ + return cext_find_item(maps, &fid, comp_fid); +} + +static Bool qfile_index(char *name, u16 * index) +{ + int i; + for (i = 0; qfilelist[i].name; i++) + if (!strncmp(name, qfilelist[i].name, strlen(qfilelist[i].name))) { + *index = i; + return True; + } + return False; +} + +static Bool make_qid(Qid * dir, char *wname, Qid * new) +{ + u16 idx; + const char *errstr; + if (dir->type != IXP_QTDIR) + return False; + new->version = 0; + if (!qfile_index(wname, &idx)) { + new->type = IXP_QTDIR; + if (!strncmp(wname, "..", 3)) { + *new = root_qid; + return True; + } else if (!strncmp(wname, "default", 8)) { + new->path = make_qpath(Ditem, 0, NONE); + return True; + } + /* check if wname is a number, otherwise file not found */ + idx = (u16) cext_strtonum(wname, 1, 0xffff, &errstr); + if (errstr || cext_sizeof(&items) < idx) + return False; + /* found */ + new->path = make_qpath(Ditem, idx, NONE); + } else { + new->type = IXP_QTFILE; + new->path = make_qpath(qfilelist[idx].type, qpath_item(dir->path), idx); + } + return True; +} + +static int attach(IXPServer *s, IXPConn *c) +{ + Container *cont = c->aux; + Map *map = cext_emallocz(sizeof(Map)); + + if (!cont) + cont = c->aux = cext_emallocz(sizeof(Container)); + fprintf(stderr, "attaching %d %s %s\n", s->fcall.afid, s->fcall.uname, s->fcall.aname); + map->qid = root_qid; + map->fid = s->fcall.fid; + cext_attach_item(cont, map); + s->fcall.id = RATTACH; + s->fcall.qid = root_qid; + return TRUE; +} + +static int walk(IXPServer * s, IXPConn * c) +{ + u16 nwqid = 0; + Qid qid; + Map *map; + + fprintf(stderr, "%s", "walking\n"); + if (!(map = fid_to_map(c->aux, s->fcall.fid))) { + s->errstr = "no directory associated with fid"; + return FALSE; + } + if (s->fcall.fid != s->fcall.newfid + && (fid_to_map(c->aux, s->fcall.newfid))) { + s->errstr = "fid alreay in use"; + return FALSE; + } + if (s->fcall.nwname) { + qid = map->qid; + for (nwqid = 0; (nwqid < s->fcall.nwname) && make_qid(&qid, s->fcall.wname[nwqid], &s->fcall.wqid[nwqid]); nwqid++) + qid = s->fcall.wqid[nwqid]; + if (!nwqid) { + s->errstr = "file not found"; + return FALSE; + } + } + /* + * following condition is required by 9P, a fid will only be valid if + * the walk was complete + */ + if (nwqid == s->fcall.nwname) { + Container *cont = c->aux; + if (s->fcall.fid == s->fcall.newfid) { + cext_detach_item(cont, map); + free(map); + } + map = cext_emallocz(sizeof(Map)); + map->qid = qid; + map->fid = s->fcall.newfid; + cext_attach_item(cont, map); + } + s->fcall.id = RWALK; + s->fcall.nwqid = nwqid; + return TRUE; +} + +static int _open(IXPServer * s, IXPConn * c) +{ + Map *map = fid_to_map(c->aux, s->fcall.fid); + + fprintf(stderr, "%s", "opening\n"); + if (!map) { + s->errstr = "invalid fid"; + return FALSE; + } + if ((s->fcall.mode != IXP_OREAD) && (s->fcall.mode != IXP_OWRITE)) { + s->errstr = "mode not supported"; + return FALSE; + } + s->fcall.id = ROPEN; + s->fcall.qid = map->qid; + s->fcall.iounit = + s->fcall.maxmsg - (sizeof(u8) + sizeof(u16) + 2 * sizeof(u32)); + return TRUE; +} + +static int _read(IXPServer * s, IXPConn * c) +{ + Map *map = fid_to_map(c->aux, s->fcall.fid); + Stat stat = { 0 }; + u8 *p; + + fprintf(stderr, "%s", "reading\n"); + if (!map) { + s->errstr = "invalid fid"; + return FALSE; + } + stat.mode = 0xff; + stat.atime = stat.mtime = time(0); + cext_strlcpy(stat.uid, getenv("USER"), sizeof(stat.uid)); + cext_strlcpy(stat.gid, getenv("USER"), sizeof(stat.gid)); + cext_strlcpy(stat.muid, getenv("USER"), sizeof(stat.muid)); + + fprintf(stderr, "%d\n", qpath_item(map->qid.path)); + switch (qpath_type(map->qid.path)) { + default: + case Droot: + p = s->fcall.data; + cext_strlcpy(stat.name, "display", sizeof(stat.name)); + stat.length = strlen(align); + make_qid(&root_qid, "display", &stat.qid); + stat.size = ixp_sizeof_stat(&stat); + s->fcall.count = stat.size; + p = ixp_enc_stat(p, &stat); + cext_strlcpy(stat.name, "font", sizeof(stat.name)); + stat.length = strlen(font); + make_qid(&root_qid, "font", &stat.qid); + stat.size = ixp_sizeof_stat(&stat);; + s->fcall.count += stat.size; + p = ixp_enc_stat(p, &stat); + cext_strlcpy(stat.name, "new", sizeof(stat.name)); + stat.length = 0; + make_qid(&root_qid, "new", &stat.qid); + stat.size = ixp_sizeof_stat(&stat);; + s->fcall.count += stat.size; + p = ixp_enc_stat(p, &stat); + s->fcall.id = RREAD; + fprintf(stderr, "%d msize\n", s->fcall.count); + break; + case Ditem: + break; + case Fdisplay: + break; + case Fnew: + break; + case Fdata: + break; + case Fevent: + break; + case Fcolor: + break; + case Ffont: + break; + } + + return TRUE; +} + +static int _write(IXPServer *s, IXPConn *c) +{ + + return FALSE; +} + +static int clunk(IXPServer *s, IXPConn *c) +{ + Container *cont = c->aux; + Map *map = fid_to_map(cont, s->fcall.fid); + + if (!map) { + s->errstr = "invalid fid"; + return FALSE; + } + cext_detach_item(cont, map); + free(map); + s->fcall.id = RCLUNK; + return TRUE; +} + +static void freeconn(IXPServer * s, IXPConn * c) +{ + Container *cont = c->aux; + if (cont) { + free(cont); + c->aux = 0; + } +} + +static IXPTFunc funcs[] = { + {TVERSION, ixp_server_tversion}, + {TATTACH, attach}, + {TWALK, walk}, + {TOPEN, _open}, + {TREAD, _read}, + {TWRITE, _write}, + {TCLUNK, clunk}, + {0, 0} +}; + +int main(int argc, char *argv[]) +{ + int i; + Item *item; + + /* command line args */ + for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) { + switch (argv[i][1]) { + case 'v': + fprintf(stdout, "%s", version[0]); + exit(0); + break; + case 's': + if (i + 1 < argc) + sockfile = argv[++i]; + else + usage(); + break; + default: + usage(); + break; + } + } + + dpy = XOpenDisplay(0); + if (!dpy) { + fprintf(stderr, "%s", "wmibar: cannot open display\n"); + exit(1); + } + XSetErrorHandler(dummy_error_handler); + screen_num = DefaultScreen(dpy); + + if (!ixp_server_init(&srv, sockfile, funcs, freeconn)) { + fprintf(stderr, "wmibar: fatal: %s\n", srv.errstr); + exit(1); + } + root_qid.type = IXP_QTDIR; + root_qid.version = 0; + root_qid.path = make_qpath(Droot, NONE, NONE); + + mypid = getpid(); + atexit(exit_cleanup); + + /* default item settings */ + item = cext_emallocz(sizeof(Item)); + + align = "bottom"; + font = "fixed"; + + ixp_server_loop(&srv); + if (srv.errstr) { + fprintf(stderr, "wmibar: fatal: %s\n", srv.errstr); + ixp_server_deinit(&srv); + exit(1); + } + ixp_server_deinit(&srv); + return 0; +} diff --git a/cmd/wmiifs.1 b/cmd/wmiifs.1 @@ -0,0 +1,38 @@ +.TH WMIFS 1 wmii-3 +.SH NAME +wmifs \- window manager improved 2 filesystem +.SH SYNOPSIS +.B wmifs +.B \-s +.I socketfile +.SH DESCRIPTION +.SS Overview +.B wmifs +is a socket-based fileserver which is used for binding other fileserver +filesystems to a specific namespace. It routes filesystem accesses to +the specific fileserver and behaves to the outside as one master +filesystem. +.SS Options +.TP +.BI \-s " socketfile" +specifies the socketfile that +.B wmifs +should create. +.TP +.B \-v +prints version information to stderr, then exits. +.SS Customization +.B wmifs +is customized through manipulating its filesystem namespace. +In the default setup of +.BR wmii (1) +the namespace of +.B wmifs +can be found in /. +.SH SEE ALSO +.BR wmibar (1), +.BR wmii (1), +.BR wmiiwm (1), +.BR wmikeys (1), +.BR wmimenu (1), +.BR wmir (1) diff --git a/cmd/wmiifs.c b/cmd/wmiifs.c @@ -0,0 +1,376 @@ +/* + * (C)opyright MMV Anselm R. Garbe <garbeam at gmail dot com> + * See LICENSE file for license details. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "wmii.h" + +/* array indexes for file pointers */ +typedef enum { + F_CTL, + F_LAST +} FsIndexes; + +typedef struct Route Route; +struct Route { + File dest; + int src; +}; + +typedef struct Bind Bind; +struct Bind { + IXPClient *client; + Route route[MAX_CONN * MAX_OPEN_FILES]; + File *mount; + char *prefix; +}; + +static Display *dpy; +static IXPServer *ixps; +static char *sockfile = 0; +static File *files[F_LAST]; +static Container bindings = {0}; + +static void quit(void *obj, char *arg); +static void bind(void *obj, char *arg); +static void unbind(void *obj, char *arg); + +static Action acttbl[] = { + {"quit", quit}, + {"unbind", unbind}, + {"bind", bind}, + {0, 0} +}; + +static char *version[] = { + "wmifs - window manager improved filesystem - " VERSION "\n" + " (C)opyright MMV Anselm R. Garbe\n", 0 +}; + +static void usage() +{ + fprintf(stderr, + "usage: wmifs -s <socket file> [-v]\n" + " -s socket file\n" " -v version info\n"); + exit(1); +} + +static void iter_unbind(void *bind, void *aux) +{ + Bind *b = bind; + if (b->mount) { + b->mount->content = 0; + ixp_remove(ixps, b->prefix); + if (ixps->errstr) + fprintf(stderr, "wmifs: error on unbind %s: %s\n", b->prefix, ixps->errstr); + } +} + +static void quit(void *obj, char *arg) +{ + cext_list_iterate(&bindings, nil, iter_unbind); + ixps->runlevel = SHUTDOWN; +} + +static void do_unbind(Bind * b) +{ + cext_detach_item(&bindings, b); + iter_unbind(b, nil); + /* free stuff */ + deinit_client(b->client); + free(b->prefix); + free(b); +} + +static int comp_bindpath(void *path, void *bind) +{ + Bind *b = bind; + return !strncmp(b->prefix, path, strlen(b->prefix)); +} + +static void unbind(void *obj, char *arg) +{ + Bind *b = cext_find_item(&bindings, arg, comp_bindpath); + + if (!b) { + fprintf(stderr, "wmifs: unbind: '%s' no such path\n", arg); + return; + } + do_unbind(b); +} + +static void bind(void *obj, char *arg) +{ + Bind *b = 0; + char cmd[1024]; + char *sfile; + + if (!arg) + return; + cext_strlcpy(cmd, arg, sizeof(cmd)); + sfile = strchr(cmd, ' '); + if (!sfile) { + fprintf(stderr, "wmifs: bind: '%s' without socket argument, ignoring\n", arg); + return; /* shortcut with empty argument */ + } + *sfile = 0; + sfile++; + if (*sfile == 0) { + fprintf(stderr, "wmifs: bind: '%s' without socket argument, ignoring\n", arg); + return; /* shortcut with empty argument */ + } + b = cext_emallocz(sizeof(Bind)); + b->client = init_ixp_client(sfile); + + if (!b->client) { + fprintf(stderr, "wmifs: bind: cannot connect to server '%s', ignoring\n", sfile); + free(b); + return; + } + b->prefix = strdup(cmd); + b->mount = ixp_create(ixps, b->prefix); + b->mount->content = b->mount; /* shall be a directory */ + + cext_attach_item(&bindings, b); +} + +static void handle_after_write(IXPServer * s, File * f) +{ + int i; + size_t len; + + for (i = 0; acttbl[i].name; 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; + } + } +} + +static Bind *fd_to_bind(int fd, int *client_fd) +{ + File *f = fd_to_file(ixps, fd); + unsigned int i, j; + Bind *b; + size_t size = cext_sizeof(&bindings); + + if (!f) + return nil; + for (i = 0; i < size; i++) { + b = cext_list_get_item(&bindings, i); + for (j = 0; j < MAX_CONN * MAX_OPEN_FILES; j++) { + if (&b->route[j].dest == f) { + *client_fd = b->route[j].src; + return b; + } + } + } + return nil; +} + +static File *fixp_create(IXPServer * s, char *path) +{ + Bind *b = cext_find_item(&bindings, path, comp_bindpath); + size_t len; + + if (!b) { + File *f = ixp_create(s, path); + return f; + } + /* route to b */ + len = strlen(b->prefix); + b->client->create(b->client, path[len] == 0 ? "/" : &path[len]); + if (b->client->errstr) { + if (!strcmp(b->client->errstr, DEAD_SERVER)) + do_unbind(b); + } + return nil; +} + +static File *fixp_open(IXPServer * s, char *path) +{ + Bind *b = cext_find_item(&bindings, path, comp_bindpath); + int fd; + size_t len; + + if (!b) { + File *f = ixp_open(s, path); + return f; + } + /* route to b */ + len = strlen(b->prefix); + fd = b->client->open(b->client, path[len] == 0 ? "/" : &path[len]); + if (b->client->errstr) { + set_error(s, b->client->errstr); + if (!strcmp(b->client->errstr, DEAD_SERVER)) + do_unbind(b); + return nil; + } + b->route[fd].src = fd; + return &b->route[fd].dest; +} + +static size_t +fixp_read(IXPServer * s, int fd, size_t offset, void *out_buf, + size_t out_buf_len) +{ + int cfd; + Bind *b = fd_to_bind(fd, &cfd); + size_t result; + + if (!b) { + result = ixp_read(s, fd, offset, out_buf, out_buf_len); + return result; + } + /* route to b */ + result = seek_read(b->client, cfd, offset, out_buf, out_buf_len); + if (b->client->errstr) { + set_error(s, b->client->errstr); + if (!strcmp(b->client->errstr, DEAD_SERVER)) + do_unbind(b); + } + return result; +} + +static void +fixp_write(IXPServer * s, int fd, size_t offset, void *content, + size_t in_len) +{ + int cfd; + Bind *b = fd_to_bind(fd, &cfd); + + if (!b) { + ixp_write(s, fd, offset, content, in_len); + return; + } + /* route to b */ + seek_write(b->client, cfd, offset, content, in_len); + if (b->client->errstr) { + set_error(s, b->client->errstr); + if (!strcmp(b->client->errstr, DEAD_SERVER)) + do_unbind(b); + } +} + +static void fixp_close(IXPServer * s, int fd) +{ + int cfd; + Bind *b = fd_to_bind(fd, &cfd); + + if (!b) { + ixp_close(s, fd); + return; + } + /* route to b */ + b->client->close(b->client, cfd); + if (b->client->errstr) { + set_error(s, b->client->errstr); + if (!strcmp(b->client->errstr, DEAD_SERVER)) + do_unbind(b); + } +} + +static void fixp_remove(IXPServer * s, char *path) +{ + Bind *b = cext_find_item(&bindings, path, comp_bindpath); + size_t len; + + if (!b) { + ixp_remove(s, path); + return; + } + /* route to b */ + len = strlen(b->prefix); + b->client->remove(b->client, path[len] == 0 ? "/" : &path[len]); + if (b->client->errstr) { + set_error(s, b->client->errstr); + if (!strcmp(b->client->errstr, DEAD_SERVER)) + do_unbind(b); + } +} + +static void check_event(Connection * e) +{ + XEvent ev; + while (XPending(dpy)) { + /* + * wmifs isn't interested in any X events, so just drop them + * all + */ + XNextEvent(dpy, &ev); + } + /* why check them? because X won't kill wmifs when X dies */ +} + +static void run() +{ + if (!(files[F_CTL] = ixp_create(ixps, "/ctl"))) { + perror("wmifs: cannot connect IXP server"); + exit(1); + } + files[F_CTL]->after_write = handle_after_write; + + /* routing functions */ + ixps->create = fixp_create; + ixps->remove = fixp_remove; + ixps->open = fixp_open; + ixps->close = fixp_close; + ixps->read = fixp_read; + ixps->write = fixp_write; + + /* main event loop */ + run_server_with_fd_support(ixps, ConnectionNumber(dpy), + check_event, 0); + + deinit_server(ixps); +} + +int main(int argc, char *argv[]) +{ + int i; + + /* command line args */ + for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) { + switch (argv[i][1]) { + case 'v': + fprintf(stdout, "%s", version[0]); + exit(0); + break; + case 's': + if (i + 1 < argc) + sockfile = argv[++i]; + else + usage(); + break; + default: + usage(); + break; + } + } + + if (!getenv("HOME")) { + fprintf(stderr, "%s", + "wmifs: $HOME environment variable is not set\n"); + usage(); + } + /* just for the case X crashes/gets quit */ + dpy = XOpenDisplay(0); + if (!dpy) { + fprintf(stderr, "%s", "wmifs: cannot open display\n"); + exit(1); + } + ixps = wmii_setup_server(sockfile); + + run(); + + return 0; +} diff --git a/cmd/wmiikeys.1 b/cmd/wmiikeys.1 @@ -0,0 +1,45 @@ +.TH WMIKEYS 1 wmii-3 +.SH NAME +wmikeys \- window manager improved 2 keys +.SH SYNOPSIS +.B wmikeys +.B \-s +.I socketfile +.SH DESCRIPTION +.SS Overview +.B wmikeys +is a generic, highly customizable, and efficient key grabbing utility for the +X Window System, originally designed for +.BR wmii (1). +It is similar to xbindkeys, but provides more flexibility and comes +with equivalent features like the ratpoison keyboard control allows. +It supports arbitrary, user defined shortcuts which are bound to +arbitrary actions. +Like wmii, +.B wmikeys +also implements a socket-based fileserver, which is accessed to configure and +interact with other components. +.SS Options +.TP +.BI \-s " socketfile" +specifies the socketfile that +.B wmikeys +should create. +.TP +.B \-v +prints version information to stderr, then exits. +.SS Customization +.B wmikeys +is customized through manipulating its filesystem namespace. +In the default setup of +.BR wmii (1) +the namespace of +.B wmikeys +can be found in /keys. +.SH SEE ALSO +.BR wmibar (1), +.BR wmifs (1), +.BR wmii (1), +.BR wmiiwm (1), +.BR wmimenu (1), +.BR wmir (1) diff --git a/cmd/wmiikeys.c b/cmd/wmiikeys.c @@ -0,0 +1,481 @@ +/* + * (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com> + * See LICENSE file for license details. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <X11/keysym.h> +#include <X11/Xatom.h> +#include <X11/cursorfont.h> +#include <X11/Xproto.h> +#include <X11/Xutil.h> + +#include "wmii.h" + +/* array indexes for file pointers */ +typedef enum { + K_CTL, + K_LOOKUP, + K_GRAB_KB, + K_FONT, + K_FG_COLOR, + K_BG_COLOR, + K_BORDER_COLOR, + K_LAST +} KeyIndexes; + +typedef struct Shortcut Shortcut; + +struct Shortcut { + char name[MAX_BUF]; + unsigned long mod; + KeyCode key; + Shortcut *next; + File *cmdfile; +}; + +static IXPServer *ixps = 0; +static Display *dpy; +static GC gc; +static Window win; +static Window root; +static XRectangle krect; +static XRectangle rect; +static int screen_num; +static char *sockfile = 0; +static Container shortcuts = {0}; +static File *files[K_LAST]; +static int grabkb = 0; +static unsigned int num_lock_mask, valid_mask; +static char buf[MAX_BUF]; +static XFontStruct *font; + +static void grab_shortcut(Shortcut * s); +static void ungrab_shortcut(Shortcut * s); +static void draw_shortcut_box(char *text); +static void quit(void *obj, char *arg); + +static Action acttbl[] = { + {"quit", quit}, + {0, 0} +}; + +static char *version[] = { + "wmikeys - window manager improved keys - " VERSION "\n" + " (C)opyright MMIV-MMV Anselm R. Garbe\n", 0 +}; + +static void usage() +{ + fprintf(stderr, "%s", + "usage: wmikeys [-s <socket file>] [-v]\n" + " -s socket file (default: /tmp/.ixp-$USER/wmikeys-$WMII_IDENT)\n" + " -v version info\n"); + exit(1); +} + +static void center() +{ + krect.x = rect.width / 2 - krect.width / 2; + krect.y = rect.height / 2 - krect.height / 2; +} + +/* grabs shortcut on all screens */ +static void grab_shortcut(Shortcut * s) +{ + XGrabKey(dpy, s->key, s->mod, root, + True, GrabModeAsync, GrabModeAsync); + if (num_lock_mask) { + XGrabKey(dpy, s->key, s->mod | num_lock_mask, root, + True, GrabModeAsync, GrabModeAsync); + XGrabKey(dpy, s->key, s->mod | num_lock_mask | LockMask, root, + True, GrabModeAsync, GrabModeAsync); + } + XSync(dpy, False); +} + +/* + * don't handle evil keys anymore, just define more shortcuts if you cannot + * live without evil key handling + */ +static void ungrab_shortcut(Shortcut * s) +{ + XUngrabKey(dpy, s->key, s->mod, root); + if (num_lock_mask) { + XUngrabKey(dpy, s->key, s->mod | num_lock_mask, root); + XUngrabKey(dpy, s->key, s->mod | num_lock_mask | LockMask, root); + } + XSync(dpy, False); +} + +static void create_shortcut(File * f) +{ + static char *chain[8]; + char *k; + size_t i, toks; + Shortcut *s = 0, *r = 0; + + cext_strlcpy(buf, f->name, sizeof(buf)); + toks = cext_tokenize(chain, 8, buf, ','); + + for (i = 0; i < toks; i++) { + if (!s) + r = s = cext_emallocz(sizeof(Shortcut)); + else { + s->next = cext_emallocz(sizeof(Shortcut)); + s = s->next; + } + cext_strlcpy(s->name, chain[i], MAX_BUF); + k = strrchr(chain[i], '-'); + if (k) + k++; + else + k = chain[i]; + s->key = XKeysymToKeycode(dpy, XStringToKeysym(k)); + s->mod = blitz_strtomod(chain[i]); + } + if (r) { + s->cmdfile = f; + cext_attach_item(&shortcuts, r); + grab_shortcut(r); + } +} + +static void destroy_shortcut(Shortcut * s, int ungrab) +{ + if (s->next) + destroy_shortcut(s->next, 0); + if (ungrab) + ungrab_shortcut(s); + free(s); +} + +static void next_keystroke(unsigned long *mod, KeyCode * key) +{ + XEvent e; + KeySym sym; + *mod = 0; + do { + XMaskEvent(dpy, KeyPressMask, &e); + *mod |= e.xkey.state & valid_mask; + *key = (KeyCode) e.xkey.keycode; + sym = XKeycodeToKeysym(dpy, e.xkey.keycode, 0); + } while (IsModifierKey(sym)); +} + +static void emulate_key_press(unsigned long mod, KeyCode key) +{ + XEvent e; + Window client_win; + int revert; + + XGetInputFocus(dpy, &client_win, &revert); + + e.xkey.type = KeyPress; + e.xkey.time = CurrentTime; + e.xkey.window = client_win; + e.xkey.display = dpy; + e.xkey.state = mod; + e.xkey.keycode = key; + XSendEvent(dpy, client_win, True, KeyPressMask, &e); + e.xkey.type = KeyRelease; + XSendEvent(dpy, client_win, True, KeyReleaseMask, &e); + XSync(dpy, False); +} + +static void handle_shortcut_chain(Window w, Shortcut * processed, char *prefix, int grab) +{ + unsigned long mod; + KeyCode key; + Shortcut *s = processed->next; + + if (grab) { + XGrabKeyboard(dpy, w, True, GrabModeAsync, GrabModeAsync, CurrentTime); + XMapRaised(dpy, win); + } + draw_shortcut_box(prefix); + next_keystroke(&mod, &key); + + if ((processed->mod == mod) && (processed->key == key)) { + /* double shortcut */ + emulate_key_press(mod, key); + } else if ((s->mod == mod) && (s->key == key)) { + if (s->cmdfile && s->cmdfile->content) + spawn(dpy, s->cmdfile->content); + else if (s->next) { + snprintf(buf, sizeof(buf), "%s/%s", prefix, s->name); + handle_shortcut_chain(w, s, buf, 0); + } + } + if (grab) { + XUngrabKeyboard(dpy, CurrentTime); + XUnmapWindow(dpy, win); + XSync(dpy, False); + } +} + +static int comp_shortcut(void *comp_short, void *shortcut) +{ + Shortcut *comp = comp_short; + Shortcut *s = shortcut; + return (s->mod == comp->mod) && (s->key == comp->key); +} + +static void handle_shortcut_gkb(Window w, unsigned long mod, KeyCode key) +{ + Shortcut comp, *s; + if (!files[K_LOOKUP]->content) + return; + + comp.mod = mod; + comp.key = key; + + s = cext_find_item(&shortcuts, &comp, comp_shortcut); + if (s && s->cmdfile && s->cmdfile->content) { + spawn(dpy, s->cmdfile->content); + return; + } + XBell(dpy, 0); +} + +static void handle_shortcut(Window w, unsigned long mod, KeyCode key) +{ + Shortcut comp, *s; + if (!files[K_LOOKUP]->content) + return; + + comp.mod = mod; + comp.key = key; + + s = cext_find_item(&shortcuts, &comp, comp_shortcut); + if (s && s->cmdfile && s->cmdfile->content) { + spawn(dpy, s->cmdfile->content); + return; + } + if (s && s->next) + handle_shortcut_chain(w, s, s->name, 1); +} + +static void quit(void *obj, char *arg) +{ + ixps->runlevel = SHUTDOWN; +} + +static void update() +{ + Shortcut *s; + File *f, *p; + if (!files[K_LOOKUP]->content) + return; + + f = ixp_walk(ixps, files[K_LOOKUP]->content); + + if (!f || !is_directory(f)) + return; /* cannot update */ + + /* destroy existing shortcuts if any */ + while ((s = cext_stack_get_top_item(&shortcuts))) { + cext_detach_item(&shortcuts, s); + destroy_shortcut(s, 1); + } + + if (grabkb) { + XGrabKeyboard(dpy, root, True, GrabModeAsync, + GrabModeAsync, CurrentTime); + return; + } + /* create new shortcuts */ + for (p = f->content; p; p = p->next) + create_shortcut(p); +} + +/* + * Function assumes following fs-structure: + * + * /box/style/font "<value>" + * /box/style/fgcolor "#RRGGBBAA" + * /box/style/bgcolor "#RRGGBBAA" + * /box/style/bordercolor "#RRGGBBAA" + */ +static void draw_shortcut_box(char *text) +{ + Draw d = { 0 }; + + d.font = font; + krect.width = XTextWidth(d.font, text, strlen(text)) + krect.height; + krect.height = font->ascent + font->descent + 4; + center(); + XMoveResizeWindow(dpy, win, krect.x, krect.y, krect.width, krect.height); + + /* default stuff */ + d.gc = gc; + d.drawable = win; + d.data = text; + d.rect.y = 0; + d.rect.width = krect.width; + d.rect.height = krect.height; + d.bg = blitz_loadcolor(dpy, screen_num, files[K_BG_COLOR]->content); + d.fg = blitz_loadcolor(dpy, screen_num, files[K_FG_COLOR]->content); + d.border = blitz_loadcolor(dpy, screen_num, files[K_BORDER_COLOR]->content); + blitz_drawlabel(dpy, &d); +} + +static void check_event(Connection * c) +{ + XEvent ev; + + while (XPending(dpy)) { + XNextEvent(dpy, &ev); + switch (ev.type) { + case KeyPress: + ev.xkey.state &= valid_mask; + if (grabkb) + handle_shortcut_gkb(root, ev.xkey.state, + (KeyCode) ev.xkey.keycode); + else + handle_shortcut(root, ev.xkey.state, + (KeyCode) ev.xkey.keycode); + break; + case KeymapNotify: + update(); + break; + default: + break; + } + } +} + +static void handle_after_write(IXPServer * s, File * f) +{ + int i; + size_t len; + + if (f == files[K_CTL]) { + for (i = 0; acttbl[i].name; 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; + } + } + } else if (f == files[K_GRAB_KB]) { + grabkb = blitz_strtonum(files[K_GRAB_KB]->content, 0, 1); + if (!grabkb) { + XUngrabKeyboard(dpy, CurrentTime); + XUnmapWindow(dpy, win); + XSync(dpy, False); + } else + update(); + } else if (f == files[K_FONT]) { + XFreeFont(dpy, font); + font = blitz_getfont(dpy, files[K_FONT]->content); + krect = rect; + krect.height = font->ascent + font->descent + 4; + center(); + XMoveResizeWindow(dpy, win, krect.x, krect.y, krect.width, krect.height); + } else if (f == files[K_LOOKUP]) { + update(); + } + check_event(0); +} + +static int dummy_error_handler(Display * dpy, XErrorEvent * err) +{ + return 0; +} + +int main(int argc, char *argv[]) +{ + int i; + XSetWindowAttributes wa; + XGCValues gcv; + + /* command line args */ + for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) { + switch (argv[i][1]) { + case 'v': + fprintf(stdout, "%s", version[0]); + exit(0); + break; + case 's': + if (i + 1 < argc) + sockfile = argv[++i]; + else + usage(); + break; + default: + usage(); + break; + } + } + + dpy = XOpenDisplay(0); + if (!dpy) { + fprintf(stderr, "%s", "wmikeys: cannot open display\n"); + exit(1); + } + XSetErrorHandler(dummy_error_handler); + screen_num = DefaultScreen(dpy); + + /* init */ + ixps = wmii_setup_server(sockfile); + + if (!(files[K_CTL] = ixp_create(ixps, "/ctl"))) { + perror("wmikeys: cannot connect IXP server"); + exit(1); + } + files[K_CTL]->after_write = handle_after_write; + files[K_LOOKUP] = ixp_create(ixps, "/lookup"); + files[K_LOOKUP]->after_write = handle_after_write; + files[K_GRAB_KB] = wmii_create_ixpfile(ixps, "/grabkeyb", "0"); + files[K_GRAB_KB]->after_write = handle_after_write; + files[K_FONT] = wmii_create_ixpfile(ixps, "/box/font", BLITZ_FONT); + files[K_FONT]->after_write = handle_after_write; + font = blitz_getfont(dpy, files[K_FONT]->content); + files[K_FG_COLOR] = wmii_create_ixpfile(ixps, "/box/fgcolor", BLITZ_SEL_FG_COLOR); + files[K_BG_COLOR] = wmii_create_ixpfile(ixps, "/box/bgcolor", BLITZ_SEL_BG_COLOR); + files[K_BORDER_COLOR] = wmii_create_ixpfile(ixps, "/box/bordercolor", BLITZ_SEL_BORDER_COLOR); + + wa.override_redirect = 1; + wa.background_pixmap = ParentRelative; + wa.event_mask = + ExposureMask | SubstructureRedirectMask | SubstructureNotifyMask; + + root = RootWindow(dpy, screen_num); + rect.x = rect.y = 0; + rect.width = DisplayWidth(dpy, screen_num); + rect.height = DisplayHeight(dpy, screen_num); + krect.x = krect.y = 0; + krect.width = krect.height = 1; + + init_lock_modifiers(dpy, &valid_mask, &num_lock_mask); + + win = XCreateWindow(dpy, RootWindow(dpy, screen_num), krect.x, krect.y, + krect.width, krect.height, 0, DefaultDepth(dpy, screen_num), + CopyFromParent, DefaultVisual(dpy, screen_num), + CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); + XDefineCursor(dpy, win, XCreateFontCursor(dpy, XC_left_ptr)); + XSync(dpy, False); + + gcv.function = GXcopy; + gcv.graphics_exposures = False; + + gc = XCreateGC(dpy, win, 0, 0); + + /* main event loop */ + run_server_with_fd_support(ixps, ConnectionNumber(dpy), + check_event, 0); + deinit_server(ixps); + XFreeGC(dpy, gc); + XCloseDisplay(dpy); + + return 0; +} diff --git a/cmd/wmiimenu.1 b/cmd/wmiimenu.1 @@ -0,0 +1,42 @@ +.TH WMIMENU 1 wmii-3 +.SH NAME +wmimenu \- window manager improved 2 menu +.SH SYNOPSIS +.B wmimenu +.B \-s +.I socketfile +.SH DESCRIPTION +.SS Overview +.B wmimenu +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 wmimenu +also implements a socket-based fileserver, which is accessed to configure and +interoperate with other components. +.SS Options +.TP +.BI \-s " socketfile" +specifies the socketfile that +.B wmimenu +should create. +.TP +.B \-v +prints version information to stderr, then exits. +.SS Customization +.B wmimenu +is customized through manipulating its filesystem namespace. +In the default setup of +.BR wmii (1) +the namespace of +.B wmimenu +can be found in /menu. +.SH SEE ALSO +.BR wmibar (1), +.BR wmifs (1), +.BR wmii (1), +.BR wmiiwm (1), +.BR wmikeys (1), +.BR wmir (1) diff --git a/cmd/wmiimenu.c b/cmd/wmiimenu.c @@ -0,0 +1,621 @@ +/* + * (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com> + * See LICENSE file for license details. + */ + +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <time.h> +#include <X11/Xatom.h> +#include <X11/cursorfont.h> +#include <X11/Xproto.h> +#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; + +enum { + OFF_NEXT, OFF_PREV, OFF_CURR, OFF_LAST +}; + +static IXPServer *ixps = 0; +static Display *dpy; +static GC gc; +static Window win; +static XRectangle rect; +static XRectangle mrect; +static int screen_num; +static char *sockfile = 0; +static File *files[M_LAST]; +static Container items = {0}; +static Container history = {0}; +static int offset[OFF_LAST]; +static unsigned int cmdw = 0; +static Pixmap pmap; +static const int seek = 30; /* 30px */ +static XFontStruct *font; +static unsigned int sel = 0; +static Align align = SOUTH; + +static void check_event(Connection * c); +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 int update_items(char *prefix); + +static Action acttbl[2] = { + {"quit", quit}, + {"display", display} +}; + +static char *version[] = { + "wmimenu - window manager improved menu - " VERSION "\n" + " (C)opyright MMIV-MMV Anselm R. Garbe\n", 0 +}; + +static void usage() +{ + fprintf(stderr, "%s", + "usage: wmimenu [-s <socket file>] [-r] [-v]\n" + " -s socket file (default: /tmp/.ixp-$USER/wmimenu-%s-%s)\n" + " -v version info\n"); + exit(1); +} + +static void add_history(char *cmd) +{ + char buf[MAX_BUF]; + snprintf(buf, MAX_BUF, "/history/%ld", (long) time(0)); + cext_attach_item(&history, wmii_create_ixpfile(ixps, buf, cmd)); +} + +static void exec_item(char *cmd) +{ + File *item = cext_list_get_item(&items, sel); + char *rc = cmd; + + if (!cmd || cmd[0] == 0) + return; + + if (item && item->size) + rc = cmd = item->content; + add_history(cmd); + + 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 */ + spawn(dpy, rc); + /* cleanup */ + if (files[M_PRE_COMMAND]->content) + free(rc); +} + +static void quit(void *obj, char *arg) +{ + ixps->runlevel = SHUTDOWN; +} + +static void show() +{ + set_text(0); + XMapRaised(dpy, win); + XSync(dpy, False); + update_items(files[M_COMMAND]->content); + draw_menu(); + while (XGrabKeyboard + (dpy, RootWindow(dpy, screen_num), True, GrabModeAsync, + GrabModeAsync, CurrentTime) != GrabSuccess) + usleep(1000); +} + +static void hide() +{ + XUngrabKeyboard(dpy, CurrentTime); + XUnmapWindow(dpy, win); + 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 (text && strlen(text)) { + files[M_COMMAND]->content = strdup(text); + files[M_COMMAND]->size = strlen(text); + } +} + +static void update_offsets() +{ + File *item; + unsigned int i, w = cmdw + 2 * seek; + + if (!cext_stack_get_top_item(&items)) + return; + + /* calc next offset */ + for (i = offset[OFF_CURR]; (item = cext_list_get_item(&items, i)); i++) { + w += XTextWidth(font, item->content, strlen(item->content)) + mrect.height; + if (w > mrect.width) + break; + } + offset[OFF_NEXT] = i; + + w = cmdw + 2 * seek; + for (i = offset[OFF_CURR] - 1; (i >= 0) && (item = cext_list_get_item(&items, i)); i--) { + w += XTextWidth(font, item->content, strlen(item->content)) + mrect.height; + if (w > mrect.width) + break; + } + offset[OFF_PREV] = i + 1; +} + +static int update_items(char *pattern) +{ + size_t plen = pattern ? strlen(pattern) : 0, len, max = 0, size; + int matched = pattern ? plen == 0 : 1; + File *f, *p, *maxitem; + + if (!files[M_LOOKUP]->content) + return 0; + f = ixp_walk(ixps, files[M_LOOKUP]->content); + if (!f || !is_directory(f)) + return 0; + + cmdw = 0; + offset[OFF_CURR] = offset[OFF_PREV] = offset[OFF_NEXT] = 0; + sel = 0; + + while ((p = cext_stack_get_top_item(&items))) + cext_detach_item(&items, p); + + /* build new items */ + for (p = f->content; p; p = p->next) { + len = strlen(p->name); + if (max < len) { + maxitem = p; + max = len; + } + } + + if (maxitem) + cmdw = XTextWidth(font, maxitem->name, max) + mrect.height; + + for (p = f->content; p; p = p->next) { + if (matched || !strncmp(pattern, p->name, plen)) { + cext_attach_item(&items, p); + p->parent = 0; /* HACK to prevent doubled items */ + } + } + + for (p = f->content; p; p = p->next) { + if (p->parent && strstr(p->name, pattern)) + cext_attach_item(&items, p); + else + p->parent = f; /* restore HACK */ + } + + size = cext_sizeof(&items); + update_offsets(); + return size; +} + +/* creates draw structs for menu mode drawing */ +static void draw_menu() +{ + Draw d = { 0 }; + unsigned int offx = 0; + int i = 0; + File *item = 0, *selitem = cext_list_get_item(&items, sel); + + d.gc = gc; + d.font = font; + d.drawable = pmap; + d.rect = mrect; + d.rect.x = 0; + d.rect.y = 0; + d.bg = blitz_loadcolor(dpy, screen_num, files[M_NORM_BG_COLOR]->content); + d.border = blitz_loadcolor(dpy, screen_num, files[M_NORM_BORDER_COLOR]->content); + blitz_drawlabelnoborder(dpy, &d); + + /* print command */ + d.align = WEST; + d.font = font; + d.fg = blitz_loadcolor(dpy, screen_num, files[M_NORM_TEXT_COLOR]->content); + d.data = files[M_COMMAND]->content; + if (cmdw && selitem) + d.rect.width = cmdw; + offx += d.rect.width; + blitz_drawlabelnoborder(dpy, &d); + + d.align = CENTER; + if (selitem) { + d.bg = blitz_loadcolor(dpy, screen_num, files[M_NORM_BG_COLOR]->content); + d.fg = blitz_loadcolor(dpy, screen_num, files[M_NORM_TEXT_COLOR]->content); + d.data = offset[OFF_CURR] ? "<" : 0; + d.rect.x = offx; + d.rect.width = seek; + offx += d.rect.width; + blitz_drawlabelnoborder(dpy, &d); + + /* determine maximum items */ + for (i = offset[OFF_CURR]; (item = cext_list_get_item(&items, i)) && (i < offset[OFF_NEXT]); i++) { + d.data = item->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 (selitem == item) { + d.bg = blitz_loadcolor(dpy, screen_num, files[M_SEL_BG_COLOR]->content); + d.fg = blitz_loadcolor(dpy, screen_num, files[M_SEL_TEXT_COLOR]->content); + d.border = blitz_loadcolor(dpy, screen_num, files[M_SEL_BORDER_COLOR]-> content); + blitz_drawlabel(dpy, &d); + } else { + d.bg = blitz_loadcolor(dpy, screen_num, files[M_NORM_BG_COLOR]->content); + d.fg = blitz_loadcolor(dpy, screen_num, files[M_NORM_TEXT_COLOR]->content); + d.border = blitz_loadcolor(dpy, screen_num, files[M_NORM_BORDER_COLOR]->content); + blitz_drawlabelnoborder(dpy, &d); + } + } + + d.bg = blitz_loadcolor(dpy, screen_num, files[M_NORM_BG_COLOR]->content); + d.fg = blitz_loadcolor(dpy, screen_num, files[M_NORM_TEXT_COLOR]->content); + d.data = item ? ">" : 0; + d.rect.x = mrect.width - seek; + d.rect.width = seek; + blitz_drawlabelnoborder(dpy, &d); + } + XCopyArea(dpy, pmap, win, gc, 0, 0, mrect.width, mrect.height, 0, 0); + XSync(dpy, False); +} + +static void handle_kpress(XKeyEvent * e) +{ + KeySym ksym; + char buf[32]; + int num; + static char text[4096]; + size_t len = 0, size = cext_sizeof(&items); + File *selitem = cext_list_get_item(&items, sel); + File *hist = cext_stack_get_top_item(&history); + + text[0] = 0; + if (files[M_COMMAND]->content) { + cext_strlcpy(text, files[M_COMMAND]->content, sizeof(text)); + len = strlen(text); + } + buf[0] = 0; + num = XLookupString(e, buf, sizeof(buf), &ksym, 0); + + if (IsFunctionKey(ksym) || IsKeypadKey(ksym) + || IsMiscFunctionKey(ksym) || IsPFKey(ksym) + || IsPrivateKeypadKey(ksym)) + return; + + /* first check if a control mask is omitted */ + if (e->state & ShiftMask) { + if (ksym == XK_ISO_Left_Tab) + ksym = XK_Left; + } else if (e->state & ControlMask) { + switch (ksym) { + case XK_E: + case XK_e: + ksym = XK_End; + break; + case XK_H: + case XK_h: + ksym = XK_BackSpace; + break; + case XK_J: + case XK_j: + ksym = XK_Return; + break; + case XK_U: + case XK_u: + set_text(0); + update_items(0); + draw_menu(); + return; + break; + default: /* ignore other control sequences */ + return; + break; + } + } + switch (ksym) { + case XK_Left: + if (!selitem) + return; + if (sel > 0) { + selitem = cext_list_get_item(&items, --sel); + set_text(selitem->name); + } else + return; + break; + case XK_Right: + case XK_Tab: + if (!selitem) + return; + if (sel < size - 1) { + selitem = cext_list_get_item(&items, ++sel); + set_text(selitem->name); + } else + return; + break; + case XK_Down: + if (hist) { + set_text(hist->content); + cext_stack_top_item(&history, cext_list_get_next_item(&items, hist)); + } + update_items(files[M_COMMAND]->content); + break; + case XK_Up: + if (hist) { + set_text(hist->content); + cext_stack_top_item(&history, cext_list_get_prev_item(&items, hist)); + } + update_items(files[M_COMMAND]->content); + break; + case XK_Return: + if (selitem) + exec_item(selitem->name); + else if (text) + exec_item(text); + case XK_Escape: + hide(); + break; + case XK_BackSpace: + if (len) { + size_t i = len; + if (i) { + do + text[--i] = 0; + while (size && i && size == update_items(text)); + } + set_text(text); + update_items(files[M_COMMAND]->content); + } + break; + default: + if ((num == 1) && !iscntrl((int) buf[0])) { + buf[num] = 0; + if (len > 0) + cext_strlcat(text, buf, sizeof(text)); + else + cext_strlcpy(text, buf, sizeof(text)); + set_text(text); + update_items(files[M_COMMAND]->content); + } + } + if (selitem) { + if (sel < offset[OFF_CURR]) { + offset[OFF_CURR] = offset[OFF_PREV]; + update_offsets(); + } else if (sel >= offset[OFF_NEXT]) { + offset[OFF_CURR] = offset[OFF_NEXT]; + update_offsets(); + } + } + draw_menu(); +} + +static void check_event(Connection * c) +{ + XEvent ev; + + while (XPending(dpy)) { + XNextEvent(dpy, &ev); + switch (ev.type) { + case KeyPress: + handle_kpress(&ev.xkey); + break; + case Expose: + if (ev.xexpose.count == 0) { + draw_menu(); + } + break; + default: + break; + } + } +} + +static void update_geometry() +{ + mrect = rect; + mrect.height = font->ascent + font->descent + 4; + if (align == SOUTH) + mrect.y = rect.height - mrect.height; + XMoveResizeWindow(dpy, win, mrect.x, mrect.y, mrect.width, mrect.height); + XSync(dpy, False); + XFreePixmap(dpy, pmap); + pmap = XCreatePixmap(dpy, win, mrect.width, mrect.height, DefaultDepth(dpy, screen_num)); + XSync(dpy, False); +} + +static void handle_after_write(IXPServer * s, File * f) +{ + 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; + } + } + } 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); +} + +int main(int argc, char *argv[]) +{ + int i; + XSetWindowAttributes wa; + XGCValues gcv; + + /* command line args */ + for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) { + switch (argv[i][1]) { + case 'v': + fprintf(stdout, "%s", version[0]); + exit(0); + break; + case 's': + if (i + 1 < argc) + sockfile = argv[++i]; + else + usage(); + break; + default: + usage(); + break; + } + } + + dpy = XOpenDisplay(0); + if (!dpy) { + fprintf(stderr, "%s", "wmimenu: cannot open display\n"); + exit(1); + } + screen_num = DefaultScreen(dpy); + + ixps = wmii_setup_server(sockfile); + + /* init */ + if (!(files[M_CTL] = ixp_create(ixps, "/ctl"))) { + perror("wmimenu: 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 + | SubstructureRedirectMask | SubstructureNotifyMask; + + rect.x = rect.y = 0; + rect.width = DisplayWidth(dpy, screen_num); + rect.height = DisplayHeight(dpy, screen_num); + mrect = rect; + mrect.height = font->ascent + font->descent + 4; + mrect.y = rect.height - mrect.height; + + win = XCreateWindow(dpy, RootWindow(dpy, screen_num), mrect.x, mrect.y, + mrect.width, mrect.height, 0, DefaultDepth(dpy, screen_num), + CopyFromParent, DefaultVisual(dpy, screen_num), + CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); + XDefineCursor(dpy, win, XCreateFontCursor(dpy, XC_xterm)); + XSync(dpy, False); + + /* window pixmap */ + gcv.function = GXcopy; + gcv.graphics_exposures = False; + + gc = XCreateGC(dpy, win, 0, 0); + pmap = XCreatePixmap(dpy, win, mrect.width, mrect.height, DefaultDepth(dpy, screen_num)); + + /* main event loop */ + run_server_with_fd_support(ixps, ConnectionNumber(dpy), check_event, 0); + deinit_server(ixps); + XFreePixmap(dpy, pmap); + XFreeGC(dpy, gc); + XCloseDisplay(dpy); + + return 0; +} diff --git a/cmd/wmiiplumb.c b/cmd/wmiiplumb.c @@ -0,0 +1,92 @@ +/* + * (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com> + * See LICENSE file for license details. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <X11/Xlib.h> +#include <X11/Xatom.h> + +static char *version[] = { + "wmiplumb - window manager improved plumb - " VERSION "\n" + " (C)opyright MMIV-MMV Anselm R. Garbe\n", 0 +}; + +static void usage() +{ + fprintf(stderr, "%s\n", + "usage: wmiplumb [-v]\n" " -v version info\n"); + exit(1); +} + +static void print_sel(Display * dpy, Window w, XSelectionEvent * e) +{ + Atom typeret; + int format; + unsigned long nitems, bytesleft; + unsigned char *data; + + XGetWindowProperty(dpy, w, e->property, 0L, 4096L, False, + AnyPropertyType, &typeret, &format, + &nitems, &bytesleft, &data); + if (format == 8) { + int i; + for (i = 0; i < nitems; i++) + putchar(data[i]); + putchar('\n'); + } + XDeleteProperty(dpy, w, e->property); +} + +int main(int argc, char **argv) +{ + Display *dpy; + Atom xa_clip_string; + Window w; + XEvent ev; + int pdone = 0; + + + /* command line args */ + if (argc > 1) { + if (!strncmp(argv[1], "-v", 3)) { + fprintf(stdout, "%s", version[0]); + exit(0); + } else + usage(); + } + dpy = XOpenDisplay(0); + if (!dpy) { + fprintf(stderr, "%s", "wmiplumb: cannot open display\n"); + exit(1); + } + xa_clip_string = XInternAtom(dpy, "PLUMB_STRING", False); + w = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 10, 10, 200, 200, + 1, CopyFromParent, CopyFromParent); + while (1 && !pdone) { + XConvertSelection(dpy, XA_PRIMARY, XA_STRING, xa_clip_string, + w, CurrentTime); + XFlush(dpy); + XNextEvent(dpy, &ev); + switch (ev.type) { + case SelectionNotify: + if (ev.xselection.property != None) + print_sel(dpy, w, &ev.xselection); + else + putchar('\n'); + XDestroyWindow(dpy, w); + XCloseDisplay(dpy); + pdone = 1; + break; + default: + break; + } + } + return 0; + /* + * XDestroyWindow(dpy, w); XCloseDisplay(dpy); return 1; + */ +} diff --git a/cmd/wmiir.1 b/cmd/wmiir.1 @@ -0,0 +1,71 @@ +.TH WMIR 1 wmii-3 +.SH NAME +wmir \- window manager improved 2 remote +.SH SYNOPSIS +.B wmir +.RB [ \-s +.IR socketfile ] +.I action +.I action_arg +[...] +.br +.B wmir +.RB [ \-s +.IR socketfile ] +.B \-f +.br +.B wmir +.B \-v +.SH DESCRIPTION +.SS Overview +.B wmir +is a client to access wmi* fileservers for the command line and +scripts. It can be used to configure wmii(1). +.SS Options +.TP +.BI \-s " socketfile" +lets you specify the socketfile to which +.B wmir +a connection will be established. If the environment variable +.B WMIR_SOCKET +is set and points to a socket file, wmir will use that file, if this +option is not supplied. +.TP +.B \-f +reads from stdin, useful for interactive wmir sessions or for +scripts that write/read a bunch of data, because this speeds things up +due to missing process creation/destruction, ie., a hack. +.TP +.B \-v +prints version information to stderr, then exits. +.TP +The syntax of the actions is as follows: +.TP +.B create <path/file> [<value>] +creates file +.TP +.B write <file> <value> +writes value to a file +.TP +.B read <path/file> +reads file or directory contents +.TP +.B remove <path/file> +removes file or directory tree +.SH ENVIRONMENT +.TP +WMIR_SOCKET +See above. +.SH EXAMPLES +.TP +$ wmir read / +This gives you an idea about what the wmii filesystem currently looks like. +.TP +$ wmir write /wm/ctl quit +.SH SEE ALSO +.BR wmibar (1), +.BR wmifs (1), +.BR wmii (1), +.BR wmiiwm (1), +.BR wmikeys (1), +.BR wmimenu (1) diff --git a/cmd/wmiir.c b/cmd/wmiir.c @@ -0,0 +1,225 @@ +/* + * (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com> + * See LICENSE file for license details. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "ixp.h" + +static IXPClient *c; +static int exit_code = 0; + +static char *version[] = { + "wmir - window manager improved remote - " VERSION "\n" + " (C)opyright MMIV-MMV Anselm R. Garbe\n", 0 +}; + +static void usage() +{ + fprintf(stderr, "%s", + "usage: wmir [-s <socket file>] [-v] <action> <action_arg> [...]\n" + " -s socket file (default: $WMIR_SOCKET)\n" + " -f read actions from stdin\n" + " -v version info\n" + "actions:\n" + " create <file> [<content>] -- creates and optionally writes content to a file\n" + " write <file> <content> -- writes content to a file\n" + " read <directory/file> -- reads file or directory contents\n" + " remove <directory/file> -- removes file or directory, use with care!\n"); + exit(1); +} + +static void perform(char *action, char *file, char *content) +{ + size_t out_len = 0; + char output[2050]; + int crt, fd = -1; + + if (!action) + return; + + crt = !strncmp(action, "create", 7); + if (!strncmp(action, "write", 6) || crt) { + if (!file) + return; + /* create file first */ + if (crt) { + c->create(c, file); + if (c->errstr) { + fprintf(stderr, "wmir: error: create %s: %s\n", file, + c->errstr); + exit_code = 1; + return; + } + } + if (!content) + return; + fd = c->open(c, file); + if (c->errstr) { + fprintf(stderr, "wmir: error: open %s: %s\n", file, c->errstr); + exit_code = 1; + return; + } + c->write(c, fd, content, strlen(content)); + if (c->errstr) { + fprintf(stderr, "wmir: error: write %s: %s\n", file, + c->errstr); + exit_code = 1; + if (!strncmp(c->errstr, DEAD_SERVER, strlen(DEAD_SERVER) + 1)) + return; + } + } else if (!strncmp(action, "read", 5)) { + if (!file) + return; + fd = c->open(c, file); + if (c->errstr) { + fprintf(stderr, "wmir: error: open %s: %s\n", file, c->errstr); + exit_code = 1; + return; + } + do { + out_len = c->read(c, fd, output, 2048); + if (c->errstr) { + fprintf(stderr, "wmir: error: read %s: %s\n", file, + c->errstr); + exit_code = 1; + if (!strncmp + (c->errstr, DEAD_SERVER, strlen(DEAD_SERVER) + 1)) + return; + break; + } + output[out_len] = 0; + fprintf(stdout, "%s", output); + } + while (out_len == 2048); + fprintf(stdout, "%s", "\n"); + } else if (!strncmp(action, "remove", 7)) { + if (!file) + return; + c->remove(c, file); + if (c->errstr) { + fprintf(stderr, "wmir: error: remove %s: %s\n", file, + c->errstr); + exit_code = 1; + return; + } + } + if (fd != -1) { + c->close(c, fd); + if (c->errstr) { + fprintf(stderr, "wmir: error: close %s: %s\n", file, + c->errstr); + exit_code = 1; + return; + } + } +} + +int main(int argc, char *argv[]) +{ + int i = 0, read_stdin = 0; + char line[4096], *p; + char *sockfile = getenv("WMIR_SOCKET"); + + /* command line args */ + if (argc > 1) { + for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) { + switch (argv[i][1]) { + case 'v': + fprintf(stderr, "%s", version[0]); + exit(0); + break; + case 's': + if (i + 1 < argc) { + sockfile = argv[++i]; + } else { + usage(); + } + break; + case 'f': + read_stdin = 1; + break; + default: + usage(); + break; + } + } + } + if ((argc <= 1) || (!read_stdin && (i + 1) >= argc)) { + fprintf(stderr, "%s", "wmir: arguments: "); + for (i = 1; i < argc; i++) + fprintf(stderr, "%s, ", argv[i]); + fprintf(stderr, "%s", "\n"); + usage(); + } + if (!sockfile) { + fprintf(stderr, "%s", + "wmir: error: WMIR_SOCKET environment not set\n"); + usage(); + } + /* open socket */ + if (!(c = init_ixp_client(sockfile))) { + fprintf(stderr, "wmir: cannot connect to server '%s'\n", sockfile); + exit(1); + } + if (read_stdin) { + /* simple shell */ + char *action, *file, *content; + while (fgets(line, 4096, stdin)) { + p = line; + while (*p != 0 && (*p == ' ' || *p == '\t')) + p++; + if (*p == 0) + continue; /* empty line */ + if (strncmp(p, "create ", 7) && + strncmp(p, "write ", 6) && + strncmp(p, "read ", 5) && strncmp(p, "remove ", 7)) + continue; + + action = p; + while (*p != 0 && *p != ' ' && *p != '\t' && *p != '\n') + p++; + if (*p == 0 || *p == '\n') + continue; /* ignore bogus command */ + *p = 0; + p++; + while (*p != 0 && (*p == ' ' || *p == '\t')) + p++; + if (*p == 0) + continue; /* ignore bogus command */ + file = p; + while (*p != 0 && *p != ' ' && *p != '\t' && *p != '\n') + p++; + if (*p == 0 || *p == '\n') { + content = 0; + *p = 0; + } else { + *p = 0; + p++; + content = p; + } + if (file[0] == 0) + continue; + if (content) { + static size_t len; + if ((len = strlen(content))) + content[len - 1] = 0; + } + perform(action, file, content); + if (c->errstr) + fprintf(stderr, "wmir: error: read %s: %s\n", file, + c->errstr); + } + } else { + perform(argv[i], argv[i + 1], (i + 2) < argc ? argv[i + 2] : 0); + } + + if (c->errstr) { + deinit_client(c); + exit_code = 1; + } + return exit_code; +} diff --git a/cmd/wmiir2.c b/cmd/wmiir2.c @@ -0,0 +1,243 @@ +/* + * (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com> + * See LICENSE file for license details. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "../libixp2/ixp.h" + +#include <cext.h> + +typedef struct { + char *name; + int (*cmd) (char **argv); + int min_argc; +} Command; + +static int xcreate(char **argv); +static int xread(char **argv); +static int xwrite(char **argv); +static int xremove(char **argv); +static Command cmds[] = { + {"create", xcreate, 2}, + {"read", xread, 1}, + {"write", xwrite, 2}, + {"remove", xremove, 1}, + {0, 0} +}; +static IXPClient c = { 0 }; + +static char *version[] = { + "wmir - window manager improved remote - " VERSION "\n" + " (C)opyright MMIV-MMV Anselm R. Garbe\n", 0 +}; + +static void usage() +{ + fprintf(stderr, "%s", + "usage: wmir [-s <socket file>] [-v] <command> <args> [...]\n" + " -s socket file (default: $WMIR_SOCKET)\n" + " -f read commands from stdin\n" + " -v version info\n" + "commands:\n" + " create <file> <content> -- creates file\n" + " read <file/directory> -- reads file/directory contents\n" + " write <file> <content> -- writes content to a file\n" + " remove <file/directory> -- removes file\n"); + exit(1); +} + +static u32 write_data(u32 fid, u8 * data, u32 count) +{ + u32 len, i, runs = count / c.fcall.iounit; + + for (i = 0; i <= runs; i++) { + /* write */ + len = count - (i * c.fcall.iounit); + if (len > c.fcall.iounit) + len = c.fcall.iounit; + if (ixp_client_write + (&c, fid, i * c.fcall.iounit, len, + &data[i * c.fcall.iounit]) != count) { + fprintf(stderr, "wmir: cannot write file: %s\n", c.errstr); + return 0; + } + } + return count; +} + +static int xcreate(char **argv) +{ + u32 fid; + char *p = strrchr(argv[0], '/'); + + fid = c.root_fid << 2; + /* walk to bottom-most directory */ + *p = 0; + if (!ixp_client_walk(&c, fid, argv[0])) { + fprintf(stderr, "wmir: cannot walk to %s: %s\n", argv[0], + c.errstr); + return 1; + } + /* create */ + p++; + if (!ixp_client_create(&c, fid, p, (u32) 0xff, IXP_OWRITE)) { + fprintf(stderr, "wmir: cannot create file: %s\n", c.errstr); + return 1; + } + write_data(fid, (u8 *) argv[1], strlen(argv[1])); + return !ixp_client_close(&c, fid); +} + +static int xwrite(char **argv) +{ + /* open */ + u32 fid = c.root_fid << 2; + if (!ixp_client_open(&c, fid, argv[0], IXP_OWRITE)) { + fprintf(stderr, "wmir: cannot open file: %s\n", c.errstr); + return 1; + } + write_data(fid, (u8 *) argv[1], strlen(argv[1])); + return !ixp_client_close(&c, fid); +} + +static void print_directory(void *result, u32 msize) +{ + void *p = result; + static Stat stat, zerostat = { 0 }; + u32 len = 0; + do { + p = ixp_dec_stat(p, &stat); + len += stat.size + sizeof(u16); + if (stat.qid.type == IXP_QTDIR) + fprintf(stdout, "%s/\n", stat.name); + else + fprintf(stdout, "%s\n", stat.name); + stat = zerostat; + } + while (len < msize); +} + +static int xread(char **argv) +{ + u32 count, fid = c.root_fid << 2; + int is_directory = FALSE; + static u8 result[IXP_MAX_MSG]; + + /* open */ + if (!ixp_client_open(&c, fid, argv[0], IXP_OREAD)) { + fprintf(stderr, "wmir: cannot open file: %s\n", c.errstr); + return 1; + } + is_directory = !c.fcall.nwqid || (c.fcall.qid.type == IXP_QTDIR); + /* read */ + if (!(count = ixp_client_read(&c, fid, 0, result, IXP_MAX_MSG)) + && c.errstr) { + fprintf(stderr, "wmir: cannot read file: %s\n", c.errstr); + return 1; + } + if (count) { + if (is_directory) + print_directory(result, count); + else { + u32 i; + for (i = 0; i < count; i++) + putchar(result[i]); + } + } + return !ixp_client_close(&c, fid); +} + +static int xremove(char **argv) +{ + u32 fid; + + /* remove */ + fid = c.root_fid << 2; + if (!ixp_client_remove(&c, fid, argv[0])) { + fprintf(stderr, "wmir: cannot remove file: %s\n", c.errstr); + return 1; + } + return 0; +} + +static int perform_cmd(int argc, char **argv) +{ + int i; + for (i = 0; cmds[i].name; i++) + if (!strncmp(cmds[i].name, argv[0], strlen(cmds[i].name))) { + if (cmds[i].min_argc <= argc) + return cmds[i].cmd(&argv[1]); + else + usage(); + } + /* bogus command */ + return 1; +} + +int main(int argc, char *argv[]) +{ + int i = 0, ret, read_stdin = 0; + char line[4096]; + char *sockfile = getenv("WMIR_SOCKET"); + + /* command line args */ + if (argc > 1) { + for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) { + switch (argv[i][1]) { + case 'v': + fprintf(stderr, "%s", version[0]); + exit(0); + break; + case 's': + if (i + 1 < argc) + sockfile = argv[++i]; + else + usage(); + break; + case 'f': + read_stdin = 1; + break; + default: + usage(); + break; + } + } + } + if ((argc <= 1) || (!read_stdin && (i + 1) >= argc)) { + fprintf(stderr, "%s", "wmir: arguments: "); + for (i = 1; i < argc; i++) + fprintf(stderr, "%s, ", argv[i]); + fprintf(stderr, "%s", "\n"); + usage(); + } + if (!sockfile) { + fprintf(stderr, "%s", + "wmir: error: WMIR_SOCKET environment not set\n"); + usage(); + } + /* open socket */ + if (!ixp_client_init(&c, sockfile)) { + fprintf(stderr, "wmir: %s\n", c.errstr); + exit(1); + } + /* wether perform directly or read from stdin */ + if (read_stdin) { + char *_argv[3]; + int _argc; + while (fgets(line, 4096, stdin)) + if ((_argc = cext_tokenize(_argv, 3, line, ' '))) { + if ((ret = perform_cmd(_argc, _argv))) + break; + } + } else + ret = perform_cmd(argc - (i + 1), &argv[i]); + + /* close socket */ + ixp_client_deinit(&c); + + return ret; +} diff --git a/cmd/wmiiwarp.c b/cmd/wmiiwarp.c @@ -0,0 +1,54 @@ +/* + * (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com> + * See LICENSE file for license details. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <X11/Xutil.h> +#include <X11/Xatom.h> + +static char *version[] = { + "wmiwarp - window manager improved warp - " VERSION "\n" + " (C)opyright MMIV-MMV Anselm R. Garbe\n", 0 +}; + +static void usage() +{ + fprintf(stderr, + "usage: wmiwarp [-v] <x>,<y>\n" " -v version info\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + Display *dpy; + int x, y; + + /* command line args */ + if (argc != 2) + usage(); + if (!strncmp(argv[1], "-v", 2)) { + fprintf(stdout, "%s", version[0]); + exit(0); + } + dpy = XOpenDisplay(0); + if (!dpy) { + fprintf(stderr, "%s", "wmiwarp: cannot open display\n"); + exit(1); + } + if (!strncmp(argv[1], "center", 7)) { + x = DisplayWidth(dpy, DefaultScreen(dpy)) / 2; + y = DisplayHeight(dpy, DefaultScreen(dpy)) / 2; + } else if (sscanf(argv[1], "%d,%d", &x, &y) != 2) { + XCloseDisplay(dpy); + usage(); + } + XWarpPointer(dpy, None, RootWindow(dpy, DefaultScreen(dpy)), + 0, 0, 0, 0, x, y); + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); + XCloseDisplay(dpy); + return 0; +} diff --git a/cmd/wmikeys.1 b/cmd/wmikeys.1 @@ -1,45 +0,0 @@ -.TH WMIKEYS 1 wmii-3 -.SH NAME -wmikeys \- window manager improved 2 keys -.SH SYNOPSIS -.B wmikeys -.B \-s -.I socketfile -.SH DESCRIPTION -.SS Overview -.B wmikeys -is a generic, highly customizable, and efficient key grabbing utility for the -X Window System, originally designed for -.BR wmii (1). -It is similar to xbindkeys, but provides more flexibility and comes -with equivalent features like the ratpoison keyboard control allows. -It supports arbitrary, user defined shortcuts which are bound to -arbitrary actions. -Like wmii, -.B wmikeys -also implements a socket-based fileserver, which is accessed to configure and -interact with other components. -.SS Options -.TP -.BI \-s " socketfile" -specifies the socketfile that -.B wmikeys -should create. -.TP -.B \-v -prints version information to stderr, then exits. -.SS Customization -.B wmikeys -is customized through manipulating its filesystem namespace. -In the default setup of -.BR wmii (1) -the namespace of -.B wmikeys -can be found in /keys. -.SH SEE ALSO -.BR wmibar (1), -.BR wmifs (1), -.BR wmii (1), -.BR wmiiwm (1), -.BR wmimenu (1), -.BR wmir (1) diff --git a/cmd/wmikeys.c b/cmd/wmikeys.c @@ -1,481 +0,0 @@ -/* - * (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <X11/keysym.h> -#include <X11/Xatom.h> -#include <X11/cursorfont.h> -#include <X11/Xproto.h> -#include <X11/Xutil.h> - -#include "wmii.h" - -/* array indexes for file pointers */ -typedef enum { - K_CTL, - K_LOOKUP, - K_GRAB_KB, - K_FONT, - K_FG_COLOR, - K_BG_COLOR, - K_BORDER_COLOR, - K_LAST -} KeyIndexes; - -typedef struct Shortcut Shortcut; - -struct Shortcut { - char name[MAX_BUF]; - unsigned long mod; - KeyCode key; - Shortcut *next; - File *cmdfile; -}; - -static IXPServer *ixps = 0; -static Display *dpy; -static GC gc; -static Window win; -static Window root; -static XRectangle krect; -static XRectangle rect; -static int screen_num; -static char *sockfile = 0; -static Container shortcuts = {0}; -static File *files[K_LAST]; -static int grabkb = 0; -static unsigned int num_lock_mask, valid_mask; -static char buf[MAX_BUF]; -static XFontStruct *font; - -static void grab_shortcut(Shortcut * s); -static void ungrab_shortcut(Shortcut * s); -static void draw_shortcut_box(char *text); -static void quit(void *obj, char *arg); - -static Action acttbl[] = { - {"quit", quit}, - {0, 0} -}; - -static char *version[] = { - "wmikeys - window manager improved keys - " VERSION "\n" - " (C)opyright MMIV-MMV Anselm R. Garbe\n", 0 -}; - -static void usage() -{ - fprintf(stderr, "%s", - "usage: wmikeys [-s <socket file>] [-v]\n" - " -s socket file (default: /tmp/.ixp-$USER/wmikeys-$WMII_IDENT)\n" - " -v version info\n"); - exit(1); -} - -static void center() -{ - krect.x = rect.width / 2 - krect.width / 2; - krect.y = rect.height / 2 - krect.height / 2; -} - -/* grabs shortcut on all screens */ -static void grab_shortcut(Shortcut * s) -{ - XGrabKey(dpy, s->key, s->mod, root, - True, GrabModeAsync, GrabModeAsync); - if (num_lock_mask) { - XGrabKey(dpy, s->key, s->mod | num_lock_mask, root, - True, GrabModeAsync, GrabModeAsync); - XGrabKey(dpy, s->key, s->mod | num_lock_mask | LockMask, root, - True, GrabModeAsync, GrabModeAsync); - } - XSync(dpy, False); -} - -/* - * don't handle evil keys anymore, just define more shortcuts if you cannot - * live without evil key handling - */ -static void ungrab_shortcut(Shortcut * s) -{ - XUngrabKey(dpy, s->key, s->mod, root); - if (num_lock_mask) { - XUngrabKey(dpy, s->key, s->mod | num_lock_mask, root); - XUngrabKey(dpy, s->key, s->mod | num_lock_mask | LockMask, root); - } - XSync(dpy, False); -} - -static void create_shortcut(File * f) -{ - static char *chain[8]; - char *k; - size_t i, toks; - Shortcut *s = 0, *r = 0; - - cext_strlcpy(buf, f->name, sizeof(buf)); - toks = cext_tokenize(chain, 8, buf, ','); - - for (i = 0; i < toks; i++) { - if (!s) - r = s = cext_emallocz(sizeof(Shortcut)); - else { - s->next = cext_emallocz(sizeof(Shortcut)); - s = s->next; - } - cext_strlcpy(s->name, chain[i], MAX_BUF); - k = strrchr(chain[i], '-'); - if (k) - k++; - else - k = chain[i]; - s->key = XKeysymToKeycode(dpy, XStringToKeysym(k)); - s->mod = blitz_strtomod(chain[i]); - } - if (r) { - s->cmdfile = f; - cext_attach_item(&shortcuts, r); - grab_shortcut(r); - } -} - -static void destroy_shortcut(Shortcut * s, int ungrab) -{ - if (s->next) - destroy_shortcut(s->next, 0); - if (ungrab) - ungrab_shortcut(s); - free(s); -} - -static void next_keystroke(unsigned long *mod, KeyCode * key) -{ - XEvent e; - KeySym sym; - *mod = 0; - do { - XMaskEvent(dpy, KeyPressMask, &e); - *mod |= e.xkey.state & valid_mask; - *key = (KeyCode) e.xkey.keycode; - sym = XKeycodeToKeysym(dpy, e.xkey.keycode, 0); - } while (IsModifierKey(sym)); -} - -static void emulate_key_press(unsigned long mod, KeyCode key) -{ - XEvent e; - Window client_win; - int revert; - - XGetInputFocus(dpy, &client_win, &revert); - - e.xkey.type = KeyPress; - e.xkey.time = CurrentTime; - e.xkey.window = client_win; - e.xkey.display = dpy; - e.xkey.state = mod; - e.xkey.keycode = key; - XSendEvent(dpy, client_win, True, KeyPressMask, &e); - e.xkey.type = KeyRelease; - XSendEvent(dpy, client_win, True, KeyReleaseMask, &e); - XSync(dpy, False); -} - -static void handle_shortcut_chain(Window w, Shortcut * processed, char *prefix, int grab) -{ - unsigned long mod; - KeyCode key; - Shortcut *s = processed->next; - - if (grab) { - XGrabKeyboard(dpy, w, True, GrabModeAsync, GrabModeAsync, CurrentTime); - XMapRaised(dpy, win); - } - draw_shortcut_box(prefix); - next_keystroke(&mod, &key); - - if ((processed->mod == mod) && (processed->key == key)) { - /* double shortcut */ - emulate_key_press(mod, key); - } else if ((s->mod == mod) && (s->key == key)) { - if (s->cmdfile && s->cmdfile->content) - spawn(dpy, s->cmdfile->content); - else if (s->next) { - snprintf(buf, sizeof(buf), "%s/%s", prefix, s->name); - handle_shortcut_chain(w, s, buf, 0); - } - } - if (grab) { - XUngrabKeyboard(dpy, CurrentTime); - XUnmapWindow(dpy, win); - XSync(dpy, False); - } -} - -static int comp_shortcut(void *comp_short, void *shortcut) -{ - Shortcut *comp = comp_short; - Shortcut *s = shortcut; - return (s->mod == comp->mod) && (s->key == comp->key); -} - -static void handle_shortcut_gkb(Window w, unsigned long mod, KeyCode key) -{ - Shortcut comp, *s; - if (!files[K_LOOKUP]->content) - return; - - comp.mod = mod; - comp.key = key; - - s = cext_find_item(&shortcuts, &comp, comp_shortcut); - if (s && s->cmdfile && s->cmdfile->content) { - spawn(dpy, s->cmdfile->content); - return; - } - XBell(dpy, 0); -} - -static void handle_shortcut(Window w, unsigned long mod, KeyCode key) -{ - Shortcut comp, *s; - if (!files[K_LOOKUP]->content) - return; - - comp.mod = mod; - comp.key = key; - - s = cext_find_item(&shortcuts, &comp, comp_shortcut); - if (s && s->cmdfile && s->cmdfile->content) { - spawn(dpy, s->cmdfile->content); - return; - } - if (s && s->next) - handle_shortcut_chain(w, s, s->name, 1); -} - -static void quit(void *obj, char *arg) -{ - ixps->runlevel = SHUTDOWN; -} - -static void update() -{ - Shortcut *s; - File *f, *p; - if (!files[K_LOOKUP]->content) - return; - - f = ixp_walk(ixps, files[K_LOOKUP]->content); - - if (!f || !is_directory(f)) - return; /* cannot update */ - - /* destroy existing shortcuts if any */ - while ((s = cext_stack_get_top_item(&shortcuts))) { - cext_detach_item(&shortcuts, s); - destroy_shortcut(s, 1); - } - - if (grabkb) { - XGrabKeyboard(dpy, root, True, GrabModeAsync, - GrabModeAsync, CurrentTime); - return; - } - /* create new shortcuts */ - for (p = f->content; p; p = p->next) - create_shortcut(p); -} - -/* - * Function assumes following fs-structure: - * - * /box/style/font "<value>" - * /box/style/fgcolor "#RRGGBBAA" - * /box/style/bgcolor "#RRGGBBAA" - * /box/style/bordercolor "#RRGGBBAA" - */ -static void draw_shortcut_box(char *text) -{ - Draw d = { 0 }; - - d.font = font; - krect.width = XTextWidth(d.font, text, strlen(text)) + krect.height; - krect.height = font->ascent + font->descent + 4; - center(); - XMoveResizeWindow(dpy, win, krect.x, krect.y, krect.width, krect.height); - - /* default stuff */ - d.gc = gc; - d.drawable = win; - d.data = text; - d.rect.y = 0; - d.rect.width = krect.width; - d.rect.height = krect.height; - d.bg = blitz_loadcolor(dpy, screen_num, files[K_BG_COLOR]->content); - d.fg = blitz_loadcolor(dpy, screen_num, files[K_FG_COLOR]->content); - d.border = blitz_loadcolor(dpy, screen_num, files[K_BORDER_COLOR]->content); - blitz_drawlabel(dpy, &d); -} - -static void check_event(Connection * c) -{ - XEvent ev; - - while (XPending(dpy)) { - XNextEvent(dpy, &ev); - switch (ev.type) { - case KeyPress: - ev.xkey.state &= valid_mask; - if (grabkb) - handle_shortcut_gkb(root, ev.xkey.state, - (KeyCode) ev.xkey.keycode); - else - handle_shortcut(root, ev.xkey.state, - (KeyCode) ev.xkey.keycode); - break; - case KeymapNotify: - update(); - break; - default: - break; - } - } -} - -static void handle_after_write(IXPServer * s, File * f) -{ - int i; - size_t len; - - if (f == files[K_CTL]) { - for (i = 0; acttbl[i].name; 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; - } - } - } else if (f == files[K_GRAB_KB]) { - grabkb = blitz_strtonum(files[K_GRAB_KB]->content, 0, 1); - if (!grabkb) { - XUngrabKeyboard(dpy, CurrentTime); - XUnmapWindow(dpy, win); - XSync(dpy, False); - } else - update(); - } else if (f == files[K_FONT]) { - XFreeFont(dpy, font); - font = blitz_getfont(dpy, files[K_FONT]->content); - krect = rect; - krect.height = font->ascent + font->descent + 4; - center(); - XMoveResizeWindow(dpy, win, krect.x, krect.y, krect.width, krect.height); - } else if (f == files[K_LOOKUP]) { - update(); - } - check_event(0); -} - -static int dummy_error_handler(Display * dpy, XErrorEvent * err) -{ - return 0; -} - -int main(int argc, char *argv[]) -{ - int i; - XSetWindowAttributes wa; - XGCValues gcv; - - /* command line args */ - for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) { - switch (argv[i][1]) { - case 'v': - fprintf(stdout, "%s", version[0]); - exit(0); - break; - case 's': - if (i + 1 < argc) - sockfile = argv[++i]; - else - usage(); - break; - default: - usage(); - break; - } - } - - dpy = XOpenDisplay(0); - if (!dpy) { - fprintf(stderr, "%s", "wmikeys: cannot open display\n"); - exit(1); - } - XSetErrorHandler(dummy_error_handler); - screen_num = DefaultScreen(dpy); - - /* init */ - ixps = wmii_setup_server(sockfile); - - if (!(files[K_CTL] = ixp_create(ixps, "/ctl"))) { - perror("wmikeys: cannot connect IXP server"); - exit(1); - } - files[K_CTL]->after_write = handle_after_write; - files[K_LOOKUP] = ixp_create(ixps, "/lookup"); - files[K_LOOKUP]->after_write = handle_after_write; - files[K_GRAB_KB] = wmii_create_ixpfile(ixps, "/grabkeyb", "0"); - files[K_GRAB_KB]->after_write = handle_after_write; - files[K_FONT] = wmii_create_ixpfile(ixps, "/box/font", BLITZ_FONT); - files[K_FONT]->after_write = handle_after_write; - font = blitz_getfont(dpy, files[K_FONT]->content); - files[K_FG_COLOR] = wmii_create_ixpfile(ixps, "/box/fgcolor", BLITZ_SEL_FG_COLOR); - files[K_BG_COLOR] = wmii_create_ixpfile(ixps, "/box/bgcolor", BLITZ_SEL_BG_COLOR); - files[K_BORDER_COLOR] = wmii_create_ixpfile(ixps, "/box/bordercolor", BLITZ_SEL_BORDER_COLOR); - - wa.override_redirect = 1; - wa.background_pixmap = ParentRelative; - wa.event_mask = - ExposureMask | SubstructureRedirectMask | SubstructureNotifyMask; - - root = RootWindow(dpy, screen_num); - rect.x = rect.y = 0; - rect.width = DisplayWidth(dpy, screen_num); - rect.height = DisplayHeight(dpy, screen_num); - krect.x = krect.y = 0; - krect.width = krect.height = 1; - - init_lock_modifiers(dpy, &valid_mask, &num_lock_mask); - - win = XCreateWindow(dpy, RootWindow(dpy, screen_num), krect.x, krect.y, - krect.width, krect.height, 0, DefaultDepth(dpy, screen_num), - CopyFromParent, DefaultVisual(dpy, screen_num), - CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); - XDefineCursor(dpy, win, XCreateFontCursor(dpy, XC_left_ptr)); - XSync(dpy, False); - - gcv.function = GXcopy; - gcv.graphics_exposures = False; - - gc = XCreateGC(dpy, win, 0, 0); - - /* main event loop */ - run_server_with_fd_support(ixps, ConnectionNumber(dpy), - check_event, 0); - deinit_server(ixps); - XFreeGC(dpy, gc); - XCloseDisplay(dpy); - - return 0; -} diff --git a/cmd/wmimenu.1 b/cmd/wmimenu.1 @@ -1,42 +0,0 @@ -.TH WMIMENU 1 wmii-3 -.SH NAME -wmimenu \- window manager improved 2 menu -.SH SYNOPSIS -.B wmimenu -.B \-s -.I socketfile -.SH DESCRIPTION -.SS Overview -.B wmimenu -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 wmimenu -also implements a socket-based fileserver, which is accessed to configure and -interoperate with other components. -.SS Options -.TP -.BI \-s " socketfile" -specifies the socketfile that -.B wmimenu -should create. -.TP -.B \-v -prints version information to stderr, then exits. -.SS Customization -.B wmimenu -is customized through manipulating its filesystem namespace. -In the default setup of -.BR wmii (1) -the namespace of -.B wmimenu -can be found in /menu. -.SH SEE ALSO -.BR wmibar (1), -.BR wmifs (1), -.BR wmii (1), -.BR wmiiwm (1), -.BR wmikeys (1), -.BR wmir (1) diff --git a/cmd/wmimenu.c b/cmd/wmimenu.c @@ -1,621 +0,0 @@ -/* - * (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ - -#include <ctype.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <time.h> -#include <X11/Xatom.h> -#include <X11/cursorfont.h> -#include <X11/Xproto.h> -#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; - -enum { - OFF_NEXT, OFF_PREV, OFF_CURR, OFF_LAST -}; - -static IXPServer *ixps = 0; -static Display *dpy; -static GC gc; -static Window win; -static XRectangle rect; -static XRectangle mrect; -static int screen_num; -static char *sockfile = 0; -static File *files[M_LAST]; -static Container items = {0}; -static Container history = {0}; -static int offset[OFF_LAST]; -static unsigned int cmdw = 0; -static Pixmap pmap; -static const int seek = 30; /* 30px */ -static XFontStruct *font; -static unsigned int sel = 0; -static Align align = SOUTH; - -static void check_event(Connection * c); -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 int update_items(char *prefix); - -static Action acttbl[2] = { - {"quit", quit}, - {"display", display} -}; - -static char *version[] = { - "wmimenu - window manager improved menu - " VERSION "\n" - " (C)opyright MMIV-MMV Anselm R. Garbe\n", 0 -}; - -static void usage() -{ - fprintf(stderr, "%s", - "usage: wmimenu [-s <socket file>] [-r] [-v]\n" - " -s socket file (default: /tmp/.ixp-$USER/wmimenu-%s-%s)\n" - " -v version info\n"); - exit(1); -} - -static void add_history(char *cmd) -{ - char buf[MAX_BUF]; - snprintf(buf, MAX_BUF, "/history/%ld", (long) time(0)); - cext_attach_item(&history, wmii_create_ixpfile(ixps, buf, cmd)); -} - -static void exec_item(char *cmd) -{ - File *item = cext_list_get_item(&items, sel); - char *rc = cmd; - - if (!cmd || cmd[0] == 0) - return; - - if (item && item->size) - rc = cmd = item->content; - add_history(cmd); - - 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 */ - spawn(dpy, rc); - /* cleanup */ - if (files[M_PRE_COMMAND]->content) - free(rc); -} - -static void quit(void *obj, char *arg) -{ - ixps->runlevel = SHUTDOWN; -} - -static void show() -{ - set_text(0); - XMapRaised(dpy, win); - XSync(dpy, False); - update_items(files[M_COMMAND]->content); - draw_menu(); - while (XGrabKeyboard - (dpy, RootWindow(dpy, screen_num), True, GrabModeAsync, - GrabModeAsync, CurrentTime) != GrabSuccess) - usleep(1000); -} - -static void hide() -{ - XUngrabKeyboard(dpy, CurrentTime); - XUnmapWindow(dpy, win); - 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 (text && strlen(text)) { - files[M_COMMAND]->content = strdup(text); - files[M_COMMAND]->size = strlen(text); - } -} - -static void update_offsets() -{ - File *item; - unsigned int i, w = cmdw + 2 * seek; - - if (!cext_stack_get_top_item(&items)) - return; - - /* calc next offset */ - for (i = offset[OFF_CURR]; (item = cext_list_get_item(&items, i)); i++) { - w += XTextWidth(font, item->content, strlen(item->content)) + mrect.height; - if (w > mrect.width) - break; - } - offset[OFF_NEXT] = i; - - w = cmdw + 2 * seek; - for (i = offset[OFF_CURR] - 1; (i >= 0) && (item = cext_list_get_item(&items, i)); i--) { - w += XTextWidth(font, item->content, strlen(item->content)) + mrect.height; - if (w > mrect.width) - break; - } - offset[OFF_PREV] = i + 1; -} - -static int update_items(char *pattern) -{ - size_t plen = pattern ? strlen(pattern) : 0, len, max = 0, size; - int matched = pattern ? plen == 0 : 1; - File *f, *p, *maxitem; - - if (!files[M_LOOKUP]->content) - return 0; - f = ixp_walk(ixps, files[M_LOOKUP]->content); - if (!f || !is_directory(f)) - return 0; - - cmdw = 0; - offset[OFF_CURR] = offset[OFF_PREV] = offset[OFF_NEXT] = 0; - sel = 0; - - while ((p = cext_stack_get_top_item(&items))) - cext_detach_item(&items, p); - - /* build new items */ - for (p = f->content; p; p = p->next) { - len = strlen(p->name); - if (max < len) { - maxitem = p; - max = len; - } - } - - if (maxitem) - cmdw = XTextWidth(font, maxitem->name, max) + mrect.height; - - for (p = f->content; p; p = p->next) { - if (matched || !strncmp(pattern, p->name, plen)) { - cext_attach_item(&items, p); - p->parent = 0; /* HACK to prevent doubled items */ - } - } - - for (p = f->content; p; p = p->next) { - if (p->parent && strstr(p->name, pattern)) - cext_attach_item(&items, p); - else - p->parent = f; /* restore HACK */ - } - - size = cext_sizeof(&items); - update_offsets(); - return size; -} - -/* creates draw structs for menu mode drawing */ -static void draw_menu() -{ - Draw d = { 0 }; - unsigned int offx = 0; - int i = 0; - File *item = 0, *selitem = cext_list_get_item(&items, sel); - - d.gc = gc; - d.font = font; - d.drawable = pmap; - d.rect = mrect; - d.rect.x = 0; - d.rect.y = 0; - d.bg = blitz_loadcolor(dpy, screen_num, files[M_NORM_BG_COLOR]->content); - d.border = blitz_loadcolor(dpy, screen_num, files[M_NORM_BORDER_COLOR]->content); - blitz_drawlabelnoborder(dpy, &d); - - /* print command */ - d.align = WEST; - d.font = font; - d.fg = blitz_loadcolor(dpy, screen_num, files[M_NORM_TEXT_COLOR]->content); - d.data = files[M_COMMAND]->content; - if (cmdw && selitem) - d.rect.width = cmdw; - offx += d.rect.width; - blitz_drawlabelnoborder(dpy, &d); - - d.align = CENTER; - if (selitem) { - d.bg = blitz_loadcolor(dpy, screen_num, files[M_NORM_BG_COLOR]->content); - d.fg = blitz_loadcolor(dpy, screen_num, files[M_NORM_TEXT_COLOR]->content); - d.data = offset[OFF_CURR] ? "<" : 0; - d.rect.x = offx; - d.rect.width = seek; - offx += d.rect.width; - blitz_drawlabelnoborder(dpy, &d); - - /* determine maximum items */ - for (i = offset[OFF_CURR]; (item = cext_list_get_item(&items, i)) && (i < offset[OFF_NEXT]); i++) { - d.data = item->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 (selitem == item) { - d.bg = blitz_loadcolor(dpy, screen_num, files[M_SEL_BG_COLOR]->content); - d.fg = blitz_loadcolor(dpy, screen_num, files[M_SEL_TEXT_COLOR]->content); - d.border = blitz_loadcolor(dpy, screen_num, files[M_SEL_BORDER_COLOR]-> content); - blitz_drawlabel(dpy, &d); - } else { - d.bg = blitz_loadcolor(dpy, screen_num, files[M_NORM_BG_COLOR]->content); - d.fg = blitz_loadcolor(dpy, screen_num, files[M_NORM_TEXT_COLOR]->content); - d.border = blitz_loadcolor(dpy, screen_num, files[M_NORM_BORDER_COLOR]->content); - blitz_drawlabelnoborder(dpy, &d); - } - } - - d.bg = blitz_loadcolor(dpy, screen_num, files[M_NORM_BG_COLOR]->content); - d.fg = blitz_loadcolor(dpy, screen_num, files[M_NORM_TEXT_COLOR]->content); - d.data = item ? ">" : 0; - d.rect.x = mrect.width - seek; - d.rect.width = seek; - blitz_drawlabelnoborder(dpy, &d); - } - XCopyArea(dpy, pmap, win, gc, 0, 0, mrect.width, mrect.height, 0, 0); - XSync(dpy, False); -} - -static void handle_kpress(XKeyEvent * e) -{ - KeySym ksym; - char buf[32]; - int num; - static char text[4096]; - size_t len = 0, size = cext_sizeof(&items); - File *selitem = cext_list_get_item(&items, sel); - File *hist = cext_stack_get_top_item(&history); - - text[0] = 0; - if (files[M_COMMAND]->content) { - cext_strlcpy(text, files[M_COMMAND]->content, sizeof(text)); - len = strlen(text); - } - buf[0] = 0; - num = XLookupString(e, buf, sizeof(buf), &ksym, 0); - - if (IsFunctionKey(ksym) || IsKeypadKey(ksym) - || IsMiscFunctionKey(ksym) || IsPFKey(ksym) - || IsPrivateKeypadKey(ksym)) - return; - - /* first check if a control mask is omitted */ - if (e->state & ShiftMask) { - if (ksym == XK_ISO_Left_Tab) - ksym = XK_Left; - } else if (e->state & ControlMask) { - switch (ksym) { - case XK_E: - case XK_e: - ksym = XK_End; - break; - case XK_H: - case XK_h: - ksym = XK_BackSpace; - break; - case XK_J: - case XK_j: - ksym = XK_Return; - break; - case XK_U: - case XK_u: - set_text(0); - update_items(0); - draw_menu(); - return; - break; - default: /* ignore other control sequences */ - return; - break; - } - } - switch (ksym) { - case XK_Left: - if (!selitem) - return; - if (sel > 0) { - selitem = cext_list_get_item(&items, --sel); - set_text(selitem->name); - } else - return; - break; - case XK_Right: - case XK_Tab: - if (!selitem) - return; - if (sel < size - 1) { - selitem = cext_list_get_item(&items, ++sel); - set_text(selitem->name); - } else - return; - break; - case XK_Down: - if (hist) { - set_text(hist->content); - cext_stack_top_item(&history, cext_list_get_next_item(&items, hist)); - } - update_items(files[M_COMMAND]->content); - break; - case XK_Up: - if (hist) { - set_text(hist->content); - cext_stack_top_item(&history, cext_list_get_prev_item(&items, hist)); - } - update_items(files[M_COMMAND]->content); - break; - case XK_Return: - if (selitem) - exec_item(selitem->name); - else if (text) - exec_item(text); - case XK_Escape: - hide(); - break; - case XK_BackSpace: - if (len) { - size_t i = len; - if (i) { - do - text[--i] = 0; - while (size && i && size == update_items(text)); - } - set_text(text); - update_items(files[M_COMMAND]->content); - } - break; - default: - if ((num == 1) && !iscntrl((int) buf[0])) { - buf[num] = 0; - if (len > 0) - cext_strlcat(text, buf, sizeof(text)); - else - cext_strlcpy(text, buf, sizeof(text)); - set_text(text); - update_items(files[M_COMMAND]->content); - } - } - if (selitem) { - if (sel < offset[OFF_CURR]) { - offset[OFF_CURR] = offset[OFF_PREV]; - update_offsets(); - } else if (sel >= offset[OFF_NEXT]) { - offset[OFF_CURR] = offset[OFF_NEXT]; - update_offsets(); - } - } - draw_menu(); -} - -static void check_event(Connection * c) -{ - XEvent ev; - - while (XPending(dpy)) { - XNextEvent(dpy, &ev); - switch (ev.type) { - case KeyPress: - handle_kpress(&ev.xkey); - break; - case Expose: - if (ev.xexpose.count == 0) { - draw_menu(); - } - break; - default: - break; - } - } -} - -static void update_geometry() -{ - mrect = rect; - mrect.height = font->ascent + font->descent + 4; - if (align == SOUTH) - mrect.y = rect.height - mrect.height; - XMoveResizeWindow(dpy, win, mrect.x, mrect.y, mrect.width, mrect.height); - XSync(dpy, False); - XFreePixmap(dpy, pmap); - pmap = XCreatePixmap(dpy, win, mrect.width, mrect.height, DefaultDepth(dpy, screen_num)); - XSync(dpy, False); -} - -static void handle_after_write(IXPServer * s, File * f) -{ - 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; - } - } - } 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); -} - -int main(int argc, char *argv[]) -{ - int i; - XSetWindowAttributes wa; - XGCValues gcv; - - /* command line args */ - for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) { - switch (argv[i][1]) { - case 'v': - fprintf(stdout, "%s", version[0]); - exit(0); - break; - case 's': - if (i + 1 < argc) - sockfile = argv[++i]; - else - usage(); - break; - default: - usage(); - break; - } - } - - dpy = XOpenDisplay(0); - if (!dpy) { - fprintf(stderr, "%s", "wmimenu: cannot open display\n"); - exit(1); - } - screen_num = DefaultScreen(dpy); - - ixps = wmii_setup_server(sockfile); - - /* init */ - if (!(files[M_CTL] = ixp_create(ixps, "/ctl"))) { - perror("wmimenu: 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 - | SubstructureRedirectMask | SubstructureNotifyMask; - - rect.x = rect.y = 0; - rect.width = DisplayWidth(dpy, screen_num); - rect.height = DisplayHeight(dpy, screen_num); - mrect = rect; - mrect.height = font->ascent + font->descent + 4; - mrect.y = rect.height - mrect.height; - - win = XCreateWindow(dpy, RootWindow(dpy, screen_num), mrect.x, mrect.y, - mrect.width, mrect.height, 0, DefaultDepth(dpy, screen_num), - CopyFromParent, DefaultVisual(dpy, screen_num), - CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); - XDefineCursor(dpy, win, XCreateFontCursor(dpy, XC_xterm)); - XSync(dpy, False); - - /* window pixmap */ - gcv.function = GXcopy; - gcv.graphics_exposures = False; - - gc = XCreateGC(dpy, win, 0, 0); - pmap = XCreatePixmap(dpy, win, mrect.width, mrect.height, DefaultDepth(dpy, screen_num)); - - /* main event loop */ - run_server_with_fd_support(ixps, ConnectionNumber(dpy), check_event, 0); - deinit_server(ixps); - XFreePixmap(dpy, pmap); - XFreeGC(dpy, gc); - XCloseDisplay(dpy); - - return 0; -} diff --git a/cmd/wmiplumb.c b/cmd/wmiplumb.c @@ -1,92 +0,0 @@ -/* - * (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#include <X11/Xlib.h> -#include <X11/Xatom.h> - -static char *version[] = { - "wmiplumb - window manager improved plumb - " VERSION "\n" - " (C)opyright MMIV-MMV Anselm R. Garbe\n", 0 -}; - -static void usage() -{ - fprintf(stderr, "%s\n", - "usage: wmiplumb [-v]\n" " -v version info\n"); - exit(1); -} - -static void print_sel(Display * dpy, Window w, XSelectionEvent * e) -{ - Atom typeret; - int format; - unsigned long nitems, bytesleft; - unsigned char *data; - - XGetWindowProperty(dpy, w, e->property, 0L, 4096L, False, - AnyPropertyType, &typeret, &format, - &nitems, &bytesleft, &data); - if (format == 8) { - int i; - for (i = 0; i < nitems; i++) - putchar(data[i]); - putchar('\n'); - } - XDeleteProperty(dpy, w, e->property); -} - -int main(int argc, char **argv) -{ - Display *dpy; - Atom xa_clip_string; - Window w; - XEvent ev; - int pdone = 0; - - - /* command line args */ - if (argc > 1) { - if (!strncmp(argv[1], "-v", 3)) { - fprintf(stdout, "%s", version[0]); - exit(0); - } else - usage(); - } - dpy = XOpenDisplay(0); - if (!dpy) { - fprintf(stderr, "%s", "wmiplumb: cannot open display\n"); - exit(1); - } - xa_clip_string = XInternAtom(dpy, "PLUMB_STRING", False); - w = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 10, 10, 200, 200, - 1, CopyFromParent, CopyFromParent); - while (1 && !pdone) { - XConvertSelection(dpy, XA_PRIMARY, XA_STRING, xa_clip_string, - w, CurrentTime); - XFlush(dpy); - XNextEvent(dpy, &ev); - switch (ev.type) { - case SelectionNotify: - if (ev.xselection.property != None) - print_sel(dpy, w, &ev.xselection); - else - putchar('\n'); - XDestroyWindow(dpy, w); - XCloseDisplay(dpy); - pdone = 1; - break; - default: - break; - } - } - return 0; - /* - * XDestroyWindow(dpy, w); XCloseDisplay(dpy); return 1; - */ -} diff --git a/cmd/wmir.1 b/cmd/wmir.1 @@ -1,71 +0,0 @@ -.TH WMIR 1 wmii-3 -.SH NAME -wmir \- window manager improved 2 remote -.SH SYNOPSIS -.B wmir -.RB [ \-s -.IR socketfile ] -.I action -.I action_arg -[...] -.br -.B wmir -.RB [ \-s -.IR socketfile ] -.B \-f -.br -.B wmir -.B \-v -.SH DESCRIPTION -.SS Overview -.B wmir -is a client to access wmi* fileservers for the command line and -scripts. It can be used to configure wmii(1). -.SS Options -.TP -.BI \-s " socketfile" -lets you specify the socketfile to which -.B wmir -a connection will be established. If the environment variable -.B WMIR_SOCKET -is set and points to a socket file, wmir will use that file, if this -option is not supplied. -.TP -.B \-f -reads from stdin, useful for interactive wmir sessions or for -scripts that write/read a bunch of data, because this speeds things up -due to missing process creation/destruction, ie., a hack. -.TP -.B \-v -prints version information to stderr, then exits. -.TP -The syntax of the actions is as follows: -.TP -.B create <path/file> [<value>] -creates file -.TP -.B write <file> <value> -writes value to a file -.TP -.B read <path/file> -reads file or directory contents -.TP -.B remove <path/file> -removes file or directory tree -.SH ENVIRONMENT -.TP -WMIR_SOCKET -See above. -.SH EXAMPLES -.TP -$ wmir read / -This gives you an idea about what the wmii filesystem currently looks like. -.TP -$ wmir write /wm/ctl quit -.SH SEE ALSO -.BR wmibar (1), -.BR wmifs (1), -.BR wmii (1), -.BR wmiiwm (1), -.BR wmikeys (1), -.BR wmimenu (1) diff --git a/cmd/wmir.c b/cmd/wmir.c @@ -1,225 +0,0 @@ -/* - * (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "ixp.h" - -static IXPClient *c; -static int exit_code = 0; - -static char *version[] = { - "wmir - window manager improved remote - " VERSION "\n" - " (C)opyright MMIV-MMV Anselm R. Garbe\n", 0 -}; - -static void usage() -{ - fprintf(stderr, "%s", - "usage: wmir [-s <socket file>] [-v] <action> <action_arg> [...]\n" - " -s socket file (default: $WMIR_SOCKET)\n" - " -f read actions from stdin\n" - " -v version info\n" - "actions:\n" - " create <file> [<content>] -- creates and optionally writes content to a file\n" - " write <file> <content> -- writes content to a file\n" - " read <directory/file> -- reads file or directory contents\n" - " remove <directory/file> -- removes file or directory, use with care!\n"); - exit(1); -} - -static void perform(char *action, char *file, char *content) -{ - size_t out_len = 0; - char output[2050]; - int crt, fd = -1; - - if (!action) - return; - - crt = !strncmp(action, "create", 7); - if (!strncmp(action, "write", 6) || crt) { - if (!file) - return; - /* create file first */ - if (crt) { - c->create(c, file); - if (c->errstr) { - fprintf(stderr, "wmir: error: create %s: %s\n", file, - c->errstr); - exit_code = 1; - return; - } - } - if (!content) - return; - fd = c->open(c, file); - if (c->errstr) { - fprintf(stderr, "wmir: error: open %s: %s\n", file, c->errstr); - exit_code = 1; - return; - } - c->write(c, fd, content, strlen(content)); - if (c->errstr) { - fprintf(stderr, "wmir: error: write %s: %s\n", file, - c->errstr); - exit_code = 1; - if (!strncmp(c->errstr, DEAD_SERVER, strlen(DEAD_SERVER) + 1)) - return; - } - } else if (!strncmp(action, "read", 5)) { - if (!file) - return; - fd = c->open(c, file); - if (c->errstr) { - fprintf(stderr, "wmir: error: open %s: %s\n", file, c->errstr); - exit_code = 1; - return; - } - do { - out_len = c->read(c, fd, output, 2048); - if (c->errstr) { - fprintf(stderr, "wmir: error: read %s: %s\n", file, - c->errstr); - exit_code = 1; - if (!strncmp - (c->errstr, DEAD_SERVER, strlen(DEAD_SERVER) + 1)) - return; - break; - } - output[out_len] = 0; - fprintf(stdout, "%s", output); - } - while (out_len == 2048); - fprintf(stdout, "%s", "\n"); - } else if (!strncmp(action, "remove", 7)) { - if (!file) - return; - c->remove(c, file); - if (c->errstr) { - fprintf(stderr, "wmir: error: remove %s: %s\n", file, - c->errstr); - exit_code = 1; - return; - } - } - if (fd != -1) { - c->close(c, fd); - if (c->errstr) { - fprintf(stderr, "wmir: error: close %s: %s\n", file, - c->errstr); - exit_code = 1; - return; - } - } -} - -int main(int argc, char *argv[]) -{ - int i = 0, read_stdin = 0; - char line[4096], *p; - char *sockfile = getenv("WMIR_SOCKET"); - - /* command line args */ - if (argc > 1) { - for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) { - switch (argv[i][1]) { - case 'v': - fprintf(stderr, "%s", version[0]); - exit(0); - break; - case 's': - if (i + 1 < argc) { - sockfile = argv[++i]; - } else { - usage(); - } - break; - case 'f': - read_stdin = 1; - break; - default: - usage(); - break; - } - } - } - if ((argc <= 1) || (!read_stdin && (i + 1) >= argc)) { - fprintf(stderr, "%s", "wmir: arguments: "); - for (i = 1; i < argc; i++) - fprintf(stderr, "%s, ", argv[i]); - fprintf(stderr, "%s", "\n"); - usage(); - } - if (!sockfile) { - fprintf(stderr, "%s", - "wmir: error: WMIR_SOCKET environment not set\n"); - usage(); - } - /* open socket */ - if (!(c = init_ixp_client(sockfile))) { - fprintf(stderr, "wmir: cannot connect to server '%s'\n", sockfile); - exit(1); - } - if (read_stdin) { - /* simple shell */ - char *action, *file, *content; - while (fgets(line, 4096, stdin)) { - p = line; - while (*p != 0 && (*p == ' ' || *p == '\t')) - p++; - if (*p == 0) - continue; /* empty line */ - if (strncmp(p, "create ", 7) && - strncmp(p, "write ", 6) && - strncmp(p, "read ", 5) && strncmp(p, "remove ", 7)) - continue; - - action = p; - while (*p != 0 && *p != ' ' && *p != '\t' && *p != '\n') - p++; - if (*p == 0 || *p == '\n') - continue; /* ignore bogus command */ - *p = 0; - p++; - while (*p != 0 && (*p == ' ' || *p == '\t')) - p++; - if (*p == 0) - continue; /* ignore bogus command */ - file = p; - while (*p != 0 && *p != ' ' && *p != '\t' && *p != '\n') - p++; - if (*p == 0 || *p == '\n') { - content = 0; - *p = 0; - } else { - *p = 0; - p++; - content = p; - } - if (file[0] == 0) - continue; - if (content) { - static size_t len; - if ((len = strlen(content))) - content[len - 1] = 0; - } - perform(action, file, content); - if (c->errstr) - fprintf(stderr, "wmir: error: read %s: %s\n", file, - c->errstr); - } - } else { - perform(argv[i], argv[i + 1], (i + 2) < argc ? argv[i + 2] : 0); - } - - if (c->errstr) { - deinit_client(c); - exit_code = 1; - } - return exit_code; -} diff --git a/cmd/wmir2.c b/cmd/wmir2.c @@ -1,243 +0,0 @@ -/* - * (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "../libixp2/ixp.h" - -#include <cext.h> - -typedef struct { - char *name; - int (*cmd) (char **argv); - int min_argc; -} Command; - -static int xcreate(char **argv); -static int xread(char **argv); -static int xwrite(char **argv); -static int xremove(char **argv); -static Command cmds[] = { - {"create", xcreate, 2}, - {"read", xread, 1}, - {"write", xwrite, 2}, - {"remove", xremove, 1}, - {0, 0} -}; -static IXPClient c = { 0 }; - -static char *version[] = { - "wmir - window manager improved remote - " VERSION "\n" - " (C)opyright MMIV-MMV Anselm R. Garbe\n", 0 -}; - -static void usage() -{ - fprintf(stderr, "%s", - "usage: wmir [-s <socket file>] [-v] <command> <args> [...]\n" - " -s socket file (default: $WMIR_SOCKET)\n" - " -f read commands from stdin\n" - " -v version info\n" - "commands:\n" - " create <file> <content> -- creates file\n" - " read <file/directory> -- reads file/directory contents\n" - " write <file> <content> -- writes content to a file\n" - " remove <file/directory> -- removes file\n"); - exit(1); -} - -static u32 write_data(u32 fid, u8 * data, u32 count) -{ - u32 len, i, runs = count / c.fcall.iounit; - - for (i = 0; i <= runs; i++) { - /* write */ - len = count - (i * c.fcall.iounit); - if (len > c.fcall.iounit) - len = c.fcall.iounit; - if (ixp_client_write - (&c, fid, i * c.fcall.iounit, len, - &data[i * c.fcall.iounit]) != count) { - fprintf(stderr, "wmir: cannot write file: %s\n", c.errstr); - return 0; - } - } - return count; -} - -static int xcreate(char **argv) -{ - u32 fid; - char *p = strrchr(argv[0], '/'); - - fid = c.root_fid << 2; - /* walk to bottom-most directory */ - *p = 0; - if (!ixp_client_walk(&c, fid, argv[0])) { - fprintf(stderr, "wmir: cannot walk to %s: %s\n", argv[0], - c.errstr); - return 1; - } - /* create */ - p++; - if (!ixp_client_create(&c, fid, p, (u32) 0xff, IXP_OWRITE)) { - fprintf(stderr, "wmir: cannot create file: %s\n", c.errstr); - return 1; - } - write_data(fid, (u8 *) argv[1], strlen(argv[1])); - return !ixp_client_close(&c, fid); -} - -static int xwrite(char **argv) -{ - /* open */ - u32 fid = c.root_fid << 2; - if (!ixp_client_open(&c, fid, argv[0], IXP_OWRITE)) { - fprintf(stderr, "wmir: cannot open file: %s\n", c.errstr); - return 1; - } - write_data(fid, (u8 *) argv[1], strlen(argv[1])); - return !ixp_client_close(&c, fid); -} - -static void print_directory(void *result, u32 msize) -{ - void *p = result; - static Stat stat, zerostat = { 0 }; - u32 len = 0; - do { - p = ixp_dec_stat(p, &stat); - len += stat.size + sizeof(u16); - if (stat.qid.type == IXP_QTDIR) - fprintf(stdout, "%s/\n", stat.name); - else - fprintf(stdout, "%s\n", stat.name); - stat = zerostat; - } - while (len < msize); -} - -static int xread(char **argv) -{ - u32 count, fid = c.root_fid << 2; - int is_directory = FALSE; - static u8 result[IXP_MAX_MSG]; - - /* open */ - if (!ixp_client_open(&c, fid, argv[0], IXP_OREAD)) { - fprintf(stderr, "wmir: cannot open file: %s\n", c.errstr); - return 1; - } - is_directory = !c.fcall.nwqid || (c.fcall.qid.type == IXP_QTDIR); - /* read */ - if (!(count = ixp_client_read(&c, fid, 0, result, IXP_MAX_MSG)) - && c.errstr) { - fprintf(stderr, "wmir: cannot read file: %s\n", c.errstr); - return 1; - } - if (count) { - if (is_directory) - print_directory(result, count); - else { - u32 i; - for (i = 0; i < count; i++) - putchar(result[i]); - } - } - return !ixp_client_close(&c, fid); -} - -static int xremove(char **argv) -{ - u32 fid; - - /* remove */ - fid = c.root_fid << 2; - if (!ixp_client_remove(&c, fid, argv[0])) { - fprintf(stderr, "wmir: cannot remove file: %s\n", c.errstr); - return 1; - } - return 0; -} - -static int perform_cmd(int argc, char **argv) -{ - int i; - for (i = 0; cmds[i].name; i++) - if (!strncmp(cmds[i].name, argv[0], strlen(cmds[i].name))) { - if (cmds[i].min_argc <= argc) - return cmds[i].cmd(&argv[1]); - else - usage(); - } - /* bogus command */ - return 1; -} - -int main(int argc, char *argv[]) -{ - int i = 0, ret, read_stdin = 0; - char line[4096]; - char *sockfile = getenv("WMIR_SOCKET"); - - /* command line args */ - if (argc > 1) { - for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) { - switch (argv[i][1]) { - case 'v': - fprintf(stderr, "%s", version[0]); - exit(0); - break; - case 's': - if (i + 1 < argc) - sockfile = argv[++i]; - else - usage(); - break; - case 'f': - read_stdin = 1; - break; - default: - usage(); - break; - } - } - } - if ((argc <= 1) || (!read_stdin && (i + 1) >= argc)) { - fprintf(stderr, "%s", "wmir: arguments: "); - for (i = 1; i < argc; i++) - fprintf(stderr, "%s, ", argv[i]); - fprintf(stderr, "%s", "\n"); - usage(); - } - if (!sockfile) { - fprintf(stderr, "%s", - "wmir: error: WMIR_SOCKET environment not set\n"); - usage(); - } - /* open socket */ - if (!ixp_client_init(&c, sockfile)) { - fprintf(stderr, "wmir: %s\n", c.errstr); - exit(1); - } - /* wether perform directly or read from stdin */ - if (read_stdin) { - char *_argv[3]; - int _argc; - while (fgets(line, 4096, stdin)) - if ((_argc = cext_tokenize(_argv, 3, line, ' '))) { - if ((ret = perform_cmd(_argc, _argv))) - break; - } - } else - ret = perform_cmd(argc - (i + 1), &argv[i]); - - /* close socket */ - ixp_client_deinit(&c); - - return ret; -} diff --git a/cmd/wmiwarp.c b/cmd/wmiwarp.c @@ -1,54 +0,0 @@ -/* - * (C)opyright MMIV-MMV Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#include <X11/Xutil.h> -#include <X11/Xatom.h> - -static char *version[] = { - "wmiwarp - window manager improved warp - " VERSION "\n" - " (C)opyright MMIV-MMV Anselm R. Garbe\n", 0 -}; - -static void usage() -{ - fprintf(stderr, - "usage: wmiwarp [-v] <x>,<y>\n" " -v version info\n"); - exit(1); -} - -int main(int argc, char **argv) -{ - Display *dpy; - int x, y; - - /* command line args */ - if (argc != 2) - usage(); - if (!strncmp(argv[1], "-v", 2)) { - fprintf(stdout, "%s", version[0]); - exit(0); - } - dpy = XOpenDisplay(0); - if (!dpy) { - fprintf(stderr, "%s", "wmiwarp: cannot open display\n"); - exit(1); - } - if (!strncmp(argv[1], "center", 7)) { - x = DisplayWidth(dpy, DefaultScreen(dpy)) / 2; - y = DisplayHeight(dpy, DefaultScreen(dpy)) / 2; - } else if (sscanf(argv[1], "%d,%d", &x, &y) != 2) { - XCloseDisplay(dpy); - usage(); - } - XWarpPointer(dpy, None, RootWindow(dpy, DefaultScreen(dpy)), - 0, 0, 0, 0, x, y); - XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); - XCloseDisplay(dpy); - return 0; -} diff --git a/rc/kmode b/rc/kmode @@ -1,11 +1,11 @@ #!9PREFIX/bin/rc # activate shortcuts of the given mode -wmir write /keys/grabkeyb 0 -wmir write /keys/lookup /mode/$1 +wmiir write /keys/grabkeyb 0 +wmiir write /keys/lookup /mode/$1 -plab_cmd=`{wmir read /wm/event/pageupdate | sed -e 's/\\//'} +plab_cmd=`{wmiir read /wm/event/pageupdate | sed -e 's/\\//'} if (! ~ $#plab_cmd 0) eval $"plab_cmd -#wmir write /bar/$plab/data \ -#`{wmir read /bar/$plab/data | sed -e 's/.$/'^`{echo $2 | cut -b1}^'/'} +#wmiir write /bar/$plab/data \ +#`{wmiir read /bar/$plab/data | sed -e 's/.$/'^`{echo $2 | cut -b1}^'/'} diff --git a/rc/quit b/rc/quit @@ -1,4 +1,4 @@ #!9PREFIX/bin/rc # quit wmii -wmir write /wm/ctl quit +wmiir write /wm/ctl quit diff --git a/rc/status b/rc/status @@ -8,22 +8,22 @@ if(test -r $PIDFILE) { } echo $pid >$PIDFILE -label=`{wmir read /bar/new} -wmir write /bar/$label/b1press 'wmir write /wm/ctl ''select prev''' -wmir write /bar/$label/b3press 'wmir write /wm/ctl ''select next''' -wmir write /bar/$label/b4press 'wmir write /wm/ctl ''select prev''' -wmir write /bar/$label/b5press 'wmir write /wm/ctl ''select next''' +label=`{wmiir read /bar/new} +wmiir write /bar/$label/b1press 'wmiir write /wm/ctl ''select prev''' +wmiir write /bar/$label/b3press 'wmiir write /wm/ctl ''select next''' +wmiir write /bar/$label/b4press 'wmiir write /wm/ctl ''select prev''' +wmiir write /bar/$label/b5press 'wmiir write /wm/ctl ''select next''' # install signal handler for artificial sigexit: fn sigint { if(test -f $PIDFILE && ~ `{cat $PIDFILE} $pid) rm -f $PIDFILE - wmir write /bar/ctl 'destroy '^$label + wmiir write /bar/ctl 'destroy '^$label exit } text=fnord -while(wmir write /bar/$label/data $"text >[2]/dev/null) { +while(wmiir write /bar/$label/data $"text >[2]/dev/null) { # if you need formatted date, use /bin/date instead text=(`{date} `{uptime | sed 's/.*://; s/,//g'}) sleep 10 diff --git a/rc/welcome b/rc/welcome @@ -49,13 +49,13 @@ Let's go! window somewhere to the left. Afterwards, swap them once again, but this time by pressing M-return. - We'll now have a look at the internal filesystem used by wmii. Executing - wmir read / + wmiir read / in the shell of the terminal will list all the files in the root directory. Files ending with a slash are directories. As you can see, / contains a "normal" file and four directories. These directories correspond to the four main components of wmii: wmiiwm, wmibar, wmikeys, and wmimenu. If you are curious, you can now dig deeper into the directory trees. For instance, - wmir read /bar/1/b1press + wmiir read /bar/1/b1press will show you which command gets executed when you left-click on the page label in the bar. diff --git a/rc/wmiirc b/rc/wmiirc @@ -0,0 +1,170 @@ +#!9PREFIX/bin/rc +# configure wmii + +TAB=0 + +SEL_BG_COLOR='#002200' +SEL_FG_COLOR='#66ff00' +SEL_BORDER_COLOR='#66ff00' +NORM_BG_COLOR='#000000' +NORM_FG_COLOR='#eeeeee' +NORM_BORDER_COLOR='#111111' +FONT='-artwiz-snap-normal-*-*-*-*-*-*-*-*-*-*-*' + +MODKEY=M +NORTHKEY=k +SOUTHKEY=j +WESTKEY=h +EASTKEY=l + +nl=' +' + +fn kbind { + wmiir create /keys/mode/$1/$2 $3 +} + +fn selstyle { + wmiir write $1/fgcolor $SEL_FG_COLOR + wmiir write $1/bgcolor $SEL_BG_COLOR + wmiir write $1/bordercolor $SEL_BORDER_COLOR +} + +fn normstyle { + wmiir write $1/fgcolor $NORM_FG_COLOR + wmiir write $1/bgcolor $NORM_BG_COLOR + wmiir write $1/bordercolor $NORM_BORDER_COLOR +} + +fn items { + ifs=:$nl { dirs=`{echo $2} } + { + for(dir in $dirs) { + for(file in $dir/*) { + if(! ~ $file $dir^'/*' && ! test -d $file && test -x $file) { + file=`{basename $file} + echo create /menu/items/$1/$"file $"file + } + } + } + } | sort | wmiir -f & +} + +fn frameconf { + wmiir write $1/event/b2press 'wmiir write /wm/ctl close' + normstyle $1/nstyle + selstyle $1/sstyle + wmiir write $1/tab $TAB + if(~ $2 refresh) + wmiir write $1/geometry +0,+0,+0,+0 # causes refresh +} + +fn framesconf { + for(frame in `{wmiir read $1 | grep '^[0-9]'}) + frameconf $1/$frame $2 +} + + +# WMIBAR CONFIGURATION + +fn barsucks { + wmiir write /bar/$1/b1press 'wmiir write /wm/ctl ''select prev''' + wmiir write /bar/$1/b3press 'wmiir write /wm/ctl ''select next''' + wmiir write /bar/$1/b4press 'wmiir write /wm/ctl ''select prev''' + wmiir write /bar/$1/b5press 'wmiir write /wm/ctl ''select next''' +} + +wmiir write /bar/ctl reset +wmiir write /bar/font $FONT +wmiir write /bar/fgcolor $NORM_FG_COLOR +wmiir write /bar/bgcolor $NORM_BG_COLOR +wmiir write /bar/bordercolor $NORM_BORDER_COLOR + +plab=`{wmiir read /bar/new} +wmiir write /bar/$plab/b1press 'wmiir write /wm/ctl pager' + +llab=`{wmiir read /bar/new} +wmiir write /bar/$llab/b1press 'wmiir write /wm/ctl pager' + +clab=`{wmiir read /bar/new} +wmiir write /bar/$clab/fgcolor $SEL_FG_COLOR +wmiir write /bar/$clab/bgcolor $SEL_BG_COLOR +wmiir write /bar/$clab/bordercolor $SEL_BG_COLOR +barsucks $clab + +wmiir write /bar/expandable $clab +wmiir write /bar/ctl 'display 1' + + +# WMIIWM CONFIGURATION + +wmiir write /wm/default/font $FONT +wmiir write /wm/default/transcolor $SEL_BORDER_COLOR +wmiir write /wm/default/handleinc 0 + +wmiir write /wm/default/border 1 +wmiir write /wm/event/clientupdate \ +'text=`{wmiir read /wm/sel/layout/sel/frame/sel/client/sel/name} \ +wmiir write /bar/'^$clab^'/data $"text' +wmiir write /wm/event/pageupdate \ +'wmiir write /bar/'^$plab^'/data `{wmiir read /wm/sel/name} &&' ^ \ +'wmiir write /bar/'^$llab^'/data `{wmiir read /wm/sel/layout/sel/name}' + +for(frame in `{wmiir read /wm/sel/layout/sel | grep '^[0-9]'}) + framesconf /wm/sel/layout/sel/$frame refresh +frameconf /wm/default norefresh + + +# WMIKEYS CONFIGURATION + +kbind bare $MODKEY-Escape 'kmode normal' + +kbind normal $MODKEY-C-b 'kmode bare' +kbind normal $MODKEY-C-a 'wmiir write /menu/precmd ''''; wmiir write /menu/lookup /items/actions; wmiir write /menu/ctl ''display 1''' +kbind normal $MODKEY-C-p 'wmiir write /menu/precmd extern; wmiir write /menu/lookup /items/programs; wmiir write /menu/ctl ''display 1''' +kbind normal $MODKEY-C-c 'wmiir write /wm/ctl close' +kbind normal $MODKEY-C-q,y quit +kbind normal $MODKEY-C-w,y wmiirc +kbind normal $MODKEY-t 'extern urxvt ''+sb'' -bg ''#000000'' -fg ''#ffffff'' -cr ''#ffffff'' -sl 4000 -fn -artwiz-smoothansi-*-*-*-*-*-*-*-*-*-*-*-*' +kbind normal $MODKEY-d 'wmiir write /wm/ctl detach' +kbind normal $MODKEY-a 'wmiir write /wm/ctl attach' +kbind normal $MODKEY-S-a 'wmiir write /wm/ctl ''detached clients''' +kbind normal $MODKEY-S-c 'wmiir write /wm/sel/layout/sel/geometry 0,0,east,south-20; wmiir write /wm/sel/layout/sel/name column' +kbind normal $MODKEY-S-n 'wmiir write /wm/sel/layout/sel/ctl new' +kbind normal $MODKEY-S-d 'wmiir write /wm/sel/layout/sel/ctl destroy' +kbind normal $MODKEY-S-f 'wmiir write /wm/sel/layout/sel/name float' +kbind normal $MODKEY-Return 'wmiir write /wm/sel/ctl ''select zoomed''' +kbind normal $MODKEY-C-y 'wmiir write /wm/ctl new' +kbind normal $MODKEY-u 'wmiir write /wm/sel/layout/sel/frame/sel/locked 0' +kbind normal $MODKEY-S-u 'wmiir write /wm/sel/layout/sel/frame/sel/locked 1' +kbind normal $MODKEY-$WESTKEY 'wmiir write /wm/ctl ''select prev''' +kbind normal $MODKEY-$EASTKEY 'wmiir write /wm/ctl ''select next''' +kbind normal $MODKEY-Tab 'wmiir write /wm/sel/layout/sel/ctl ''select next''' +kbind normal $MODKEY-$SOUTHKEY 'wmiir write /wm/sel/layout/sel/ctl ''select next''' +kbind normal $MODKEY-$NORTHKEY 'wmiir write /wm/sel/layout/sel/ctl ''select prev''' +kbind normal $MODKEY-S-$WESTKEY 'wmiir write /wm/sel/layout/sel/ctl ''select west''' +kbind normal $MODKEY-S-$EASTKEY 'wmiir write /wm/sel/layout/sel/ctl ''select east''' +kbind normal $MODKEY-S-Tab 'wmiir write /wm/sel/layout/sel/frame/sel/ctl ''select next''' +kbind normal $MODKEY-S-$SOUTHKEY 'wmiir write /wm/sel/layout/sel/frame/sel/ctl ''select next''' +kbind normal $MODKEY-S-$NORTHKEY 'wmiir write /wm/sel/layout/sel/frame/sel/ctl ''select prev''' +kbind normal $MODKEY-space 'wmiir write /wm/sel/ctl ''select toggled''' +kbind normal $MODKEY-S-p 'wmiir write /wm/ctl pager' +for(i in 0 1 2 3 4 5 6 7 8 9) { + kbind normal $MODKEY-S-$i 'wmiir write /wm/ctl ''select '^$i^'''' +} + +wmiir write /keys/box/font $FONT +selstyle /keys/box +kmode normal + +# WMIMENU CONFIGURATION +items actions $WMII_CONFDIR:$HOME/.wmii-3 +wmiir create /menu/items/actions/rmpage 'wmiir write /wm/ctl destroy' +items programs $OLD_PATH +wmiir write /menu/font $FONT +normstyle /menu/nstyle >[2]/dev/null +selstyle /menu/sstyle >[2]/dev/null + +# MISC +xsetroot -solid black +status& diff --git a/rc/wmirc b/rc/wmirc @@ -1,170 +0,0 @@ -#!9PREFIX/bin/rc -# configure wmii - -TAB=0 - -SEL_BG_COLOR='#002200' -SEL_FG_COLOR='#66ff00' -SEL_BORDER_COLOR='#66ff00' -NORM_BG_COLOR='#000000' -NORM_FG_COLOR='#eeeeee' -NORM_BORDER_COLOR='#111111' -FONT='-artwiz-snap-normal-*-*-*-*-*-*-*-*-*-*-*' - -MODKEY=M -NORTHKEY=k -SOUTHKEY=j -WESTKEY=h -EASTKEY=l - -nl=' -' - -fn kbind { - wmir create /keys/mode/$1/$2 $3 -} - -fn selstyle { - wmir write $1/fgcolor $SEL_FG_COLOR - wmir write $1/bgcolor $SEL_BG_COLOR - wmir write $1/bordercolor $SEL_BORDER_COLOR -} - -fn normstyle { - wmir write $1/fgcolor $NORM_FG_COLOR - wmir write $1/bgcolor $NORM_BG_COLOR - wmir write $1/bordercolor $NORM_BORDER_COLOR -} - -fn items { - ifs=:$nl { dirs=`{echo $2} } - { - for(dir in $dirs) { - for(file in $dir/*) { - if(! ~ $file $dir^'/*' && ! test -d $file && test -x $file) { - file=`{basename $file} - echo create /menu/items/$1/$"file $"file - } - } - } - } | sort | wmir -f & -} - -fn frameconf { - wmir write $1/event/b2press 'wmir write /wm/ctl close' - normstyle $1/nstyle - selstyle $1/sstyle - wmir write $1/tab $TAB - if(~ $2 refresh) - wmir write $1/geometry +0,+0,+0,+0 # causes refresh -} - -fn framesconf { - for(frame in `{wmir read $1 | grep '^[0-9]'}) - frameconf $1/$frame $2 -} - - -# WMIBAR CONFIGURATION - -fn barsucks { - wmir write /bar/$1/b1press 'wmir write /wm/ctl ''select prev''' - wmir write /bar/$1/b3press 'wmir write /wm/ctl ''select next''' - wmir write /bar/$1/b4press 'wmir write /wm/ctl ''select prev''' - wmir write /bar/$1/b5press 'wmir write /wm/ctl ''select next''' -} - -wmir write /bar/ctl reset -wmir write /bar/font $FONT -wmir write /bar/fgcolor $NORM_FG_COLOR -wmir write /bar/bgcolor $NORM_BG_COLOR -wmir write /bar/bordercolor $NORM_BORDER_COLOR - -plab=`{wmir read /bar/new} -wmir write /bar/$plab/b1press 'wmir write /wm/ctl pager' - -llab=`{wmir read /bar/new} -wmir write /bar/$llab/b1press 'wmir write /wm/ctl pager' - -clab=`{wmir read /bar/new} -wmir write /bar/$clab/fgcolor $SEL_FG_COLOR -wmir write /bar/$clab/bgcolor $SEL_BG_COLOR -wmir write /bar/$clab/bordercolor $SEL_BG_COLOR -barsucks $clab - -wmir write /bar/expandable $clab -wmir write /bar/ctl 'display 1' - - -# WMIIWM CONFIGURATION - -wmir write /wm/default/font $FONT -wmir write /wm/default/transcolor $SEL_BORDER_COLOR -wmir write /wm/default/handleinc 0 - -wmir write /wm/default/border 1 -wmir write /wm/event/clientupdate \ -'text=`{wmir read /wm/sel/layout/sel/frame/sel/client/sel/name} \ -wmir write /bar/'^$clab^'/data $"text' -wmir write /wm/event/pageupdate \ -'wmir write /bar/'^$plab^'/data `{wmir read /wm/sel/name} &&' ^ \ -'wmir write /bar/'^$llab^'/data `{wmir read /wm/sel/layout/sel/name}' - -for(frame in `{wmir read /wm/sel/layout/sel | grep '^[0-9]'}) - framesconf /wm/sel/layout/sel/$frame refresh -frameconf /wm/default norefresh - - -# WMIKEYS CONFIGURATION - -kbind bare $MODKEY-Escape 'kmode normal' - -kbind normal $MODKEY-C-b 'kmode bare' -kbind normal $MODKEY-C-a 'wmir write /menu/precmd ''''; wmir write /menu/lookup /items/actions; wmir write /menu/ctl ''display 1''' -kbind normal $MODKEY-C-p 'wmir write /menu/precmd extern; wmir write /menu/lookup /items/programs; wmir write /menu/ctl ''display 1''' -kbind normal $MODKEY-C-c 'wmir write /wm/ctl close' -kbind normal $MODKEY-C-q,y quit -kbind normal $MODKEY-C-w,y wmirc -kbind normal $MODKEY-t 'extern urxvt ''+sb'' -bg ''#000000'' -fg ''#ffffff'' -cr ''#ffffff'' -sl 4000 -fn -artwiz-smoothansi-*-*-*-*-*-*-*-*-*-*-*-*' -kbind normal $MODKEY-d 'wmir write /wm/ctl detach' -kbind normal $MODKEY-a 'wmir write /wm/ctl attach' -kbind normal $MODKEY-S-a 'wmir write /wm/ctl ''detached clients''' -kbind normal $MODKEY-S-c 'wmir write /wm/sel/layout/sel/geometry 0,0,east,south-20; wmir write /wm/sel/layout/sel/name column' -kbind normal $MODKEY-S-n 'wmir write /wm/sel/layout/sel/ctl new' -kbind normal $MODKEY-S-d 'wmir write /wm/sel/layout/sel/ctl destroy' -kbind normal $MODKEY-S-f 'wmir write /wm/sel/layout/sel/name float' -kbind normal $MODKEY-Return 'wmir write /wm/sel/ctl ''select zoomed''' -kbind normal $MODKEY-C-y 'wmir write /wm/ctl new' -kbind normal $MODKEY-u 'wmir write /wm/sel/layout/sel/frame/sel/locked 0' -kbind normal $MODKEY-S-u 'wmir write /wm/sel/layout/sel/frame/sel/locked 1' -kbind normal $MODKEY-$WESTKEY 'wmir write /wm/ctl ''select prev''' -kbind normal $MODKEY-$EASTKEY 'wmir write /wm/ctl ''select next''' -kbind normal $MODKEY-Tab 'wmir write /wm/sel/layout/sel/ctl ''select next''' -kbind normal $MODKEY-$SOUTHKEY 'wmir write /wm/sel/layout/sel/ctl ''select next''' -kbind normal $MODKEY-$NORTHKEY 'wmir write /wm/sel/layout/sel/ctl ''select prev''' -kbind normal $MODKEY-S-$WESTKEY 'wmir write /wm/sel/layout/sel/ctl ''select west''' -kbind normal $MODKEY-S-$EASTKEY 'wmir write /wm/sel/layout/sel/ctl ''select east''' -kbind normal $MODKEY-S-Tab 'wmir write /wm/sel/layout/sel/frame/sel/ctl ''select next''' -kbind normal $MODKEY-S-$SOUTHKEY 'wmir write /wm/sel/layout/sel/frame/sel/ctl ''select next''' -kbind normal $MODKEY-S-$NORTHKEY 'wmir write /wm/sel/layout/sel/frame/sel/ctl ''select prev''' -kbind normal $MODKEY-space 'wmir write /wm/sel/ctl ''select toggled''' -kbind normal $MODKEY-S-p 'wmir write /wm/ctl pager' -for(i in 0 1 2 3 4 5 6 7 8 9) { - kbind normal $MODKEY-S-$i 'wmir write /wm/ctl ''select '^$i^'''' -} - -wmir write /keys/box/font $FONT -selstyle /keys/box -kmode normal - -# WMIMENU CONFIGURATION -items actions $WMII_CONFDIR:$HOME/.wmii-3 -wmir create /menu/items/actions/rmpage 'wmir write /wm/ctl destroy' -items programs $OLD_PATH -wmir write /menu/font $FONT -normstyle /menu/nstyle >[2]/dev/null -selstyle /menu/sstyle >[2]/dev/null - -# MISC -xsetroot -solid black -status&