wmii

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

commit 32fc2e2c6631605c71b588d2dc7f13a58466ebd5
parent 979a99d7d2f6bbb76de3552a9e4c6214960a2fec
Author: Anselm R. Garbe <garbeam@wmii.de>
Date:   Mon,  6 Feb 2006 15:08:32 +0200

adding wmiikeys (9Pization in progress)


Diffstat:
cmd/Makefile | 2+-
cmd/wmiibar.c | 5++---
cmd/wmiikeys.c | 906+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
3 files changed, 705 insertions(+), 208 deletions(-)

diff --git a/cmd/Makefile b/cmd/Makefile @@ -29,7 +29,7 @@ SRC_warp = wmiiwarp.c OBJ_warp = ${SRC_warp:.c=.o} #all: wmiibar wmiimenu wmiir wmiifs wmiikeys wmiiplumb wmiiwarp -all: wmiibar wmiir wmiiplumb wmiiwarp +all: wmiikeys wmiibar wmiir wmiiplumb wmiiwarp @echo built wmii commands .c.o: diff --git a/cmd/wmiibar.c b/cmd/wmiibar.c @@ -18,8 +18,7 @@ #include <X11/Xutil.h> #include <sys/socket.h> -#include "ixp.h" -#include "blitz.h" +#include "wmii.h" /* * filesystem specification @@ -233,7 +232,7 @@ check_x_event(IXPConn *c) } } -int +static int index_of_id(unsigned short id) { int i; diff --git a/cmd/wmiikeys.c b/cmd/wmiikeys.c @@ -17,54 +17,64 @@ #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; +/* + * filesystem specification + * / Droot + * /font Ffont <xlib font name> + * /color Fcolor <#RRGGBB> <#RRGGBB> <#RRGGBB> + * /ctl Fctl command interface + * /reset Freset setup interface + * /shortcut/ Dshortcut + * /shortcut/foo Fshortcut shortcut file + */ + +/* 8-bit qid.path.type */ +enum { + Droot, + Dshortcut + Fctl, + Ffont, + Fcolor, + Freset, + Fshortcut +}; typedef struct Shortcut Shortcut; struct Shortcut { + unsigned short id; char name[MAX_BUF]; + char *cmd; unsigned long mod; KeyCode key; - File *cmdfile; - Shortcut *snext; Shortcut *next; }; -static IXPServer *ixps = nil; +static char E9pversion[] = "9P version not supported"; +static char Enoperm[] = "permission denied"; +static char Enofid[] = "fid not assigned"; +static char Enofile[] = "file not found"; +static char Enomode[] = "mode not supported"; +static char Enofunc[] = "function not supported"; +static char Enocommand[] = "command not supported"; + + +static IXPServer srv; static Display *dpy; -static GC gc; static Window win; static Window root; -static XRectangle krect; static XRectangle rect; static int screen; -static char *sockfile = nil; -static Shortcut *shortcuts = nil; -static File *files[K_LAST]; +static Shortcut **shortcut = nil; +static size_t shortcutsz = 0; +static size_t nshortcut = 0; static int grabkb = 0; static unsigned int num_lock_mask, valid_mask; -static char buf[MAX_BUF]; -static XFontStruct *font; +static char *font; +static char *colstr; +static Draw box; -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 void draw_shortcut_box(char *prefix); static char version[] = "wmiikeys - " VERSION ", (C)opyright MMIV-MMVI Anselm R. Garbe\n"; @@ -75,14 +85,17 @@ usage() exit(1); } +/* X stuff */ + static void center() { - krect.x = rect.width / 2 - krect.width / 2; - krect.y = rect.height / 2 - krect.height / 2; + int x = rect.width / 2 - box.rect.width / 2; + int y = rect.height / 2 - box.rect.height / 2; + XMoveResizeWindow(dpy, win, x, y, box.rect.width, box.rect.height); + XSync(dpy, False); } -/* grabs shortcut on all screens */ static void grab_shortcut(Shortcut * s) { @@ -97,10 +110,6 @@ grab_shortcut(Shortcut * s) 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) { @@ -112,23 +121,25 @@ ungrab_shortcut(Shortcut * s) XSync(dpy, False); } -static void -create_shortcut(File * f) +static Shortcut * +create_shortcut(char *name, char *cmd) { - static char *chain[8]; + char buf[256]; + char *chain[8]; char *k; size_t i, toks; + static unsigned short id = 1; Shortcut *s = 0, *r = 0; - cext_strlcpy(buf, f->name, sizeof(buf)); + cext_strlcpy(buf, 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->snext = cext_emallocz(sizeof(Shortcut)); - s = s->snext; + s->next = cext_emallocz(sizeof(Shortcut)); + s = s->next; } cext_strlcpy(s->name, chain[i], MAX_BUF); k = strrchr(chain[i], '-'); @@ -139,30 +150,30 @@ create_shortcut(File * f) s->key = XKeysymToKeycode(dpy, XStringToKeysym(k)); s->mod = blitz_strtomod(chain[i]); } + r->id = id++; + return r; + +} + +/* create if(r) { - s->cmdfile = f; - if(!shortcuts) - shortcuts = r; - else { - for(s = shortcuts; s && s->next; s = s->next); - s->next = r; - } + s->cmd = cmd; + shortcut = (Shortcut **)cext_attach_array((void **)shortcut, r, &shortcutsz); + nshortcut++; grab_shortcut(r); } -} + */ static void -destroy_shortcut(Shortcut * s, int ungrab) +destroy_shortcut(Shortcut *s) { - if(s->snext) - destroy_shortcut(s->snext, 0); - if(ungrab) - ungrab_shortcut(s); + if(s->next) + destroy_shortcut(s->next); free(s); } static void -next_keystroke(unsigned long *mod, KeyCode * key) +next_keystroke(unsigned long *mod, KeyCode *key) { XEvent e; KeySym sym; @@ -197,18 +208,13 @@ emulate_key_press(unsigned long mod, KeyCode key) } static void -handle_shortcut_chain(Window w, Shortcut * processed, char *prefix, - int grab) +handle_shortcut_chain(Window w, Shortcut *processed, char *prefix) { + char buf[256]; unsigned long mod; KeyCode key; - Shortcut *s = processed->snext; + Shortcut *s = processed->next; - if(grab) { - XGrabKeyboard(dpy, w, True, GrabModeAsync, GrabModeAsync, - CurrentTime); - XMapRaised(dpy, win); - } draw_shortcut_box(prefix); next_keystroke(&mod, &key); @@ -216,32 +222,26 @@ handle_shortcut_chain(Window w, Shortcut * processed, char *prefix, /* double shortcut */ emulate_key_press(mod, key); } else if((s->mod == mod) && (s->key == key)) { - if(s->cmdfile && s->cmdfile->content) - wmii_spawn(dpy, s->cmdfile->content); - else if(s->snext) { + if(s->cmd) + wmii_spawn(dpy, s->cmd); + else if(s->next) { snprintf(buf, sizeof(buf), "%s/%s", prefix, s->name); - handle_shortcut_chain(w, s, buf, 0); + handle_shortcut_chain(w, s, buf); } } - if(grab) { - XUngrabKeyboard(dpy, CurrentTime); - XUnmapWindow(dpy, win); - XSync(dpy, False); - } } static void handle_shortcut_gkb(Window w, unsigned long mod, KeyCode key) { - Shortcut *s; - if(!files[K_LOOKUP]->content) - return; - - for(s = shortcuts; s && ((s->mod != mod) || (s->key != key)); - s = s->next); - if(s && s->cmdfile && s->cmdfile->content) { - wmii_spawn(dpy, s->cmdfile->content); - return; + size_t i; + for(i = 0; i < nshortcut; i++) { + Shortcut *s = shortcut[i]; + if((s->mod == mod) && (s->key == key)) { + if(s->cmd) + wmii_spawn(dpy, s->cmd); + return; + } } XBell(dpy, 0); } @@ -249,109 +249,63 @@ handle_shortcut_gkb(Window w, unsigned long mod, KeyCode key) static void handle_shortcut(Window w, unsigned long mod, KeyCode key) { - Shortcut *s; - if(!files[K_LOOKUP]->content) - return; - - for(s = shortcuts; s && ((s->mod != mod) || (s->key != key)); - s = s->next); - if(s && s->cmdfile && s->cmdfile->content) { - wmii_spawn(dpy, s->cmdfile->content); - return; - } - if(s && s->snext) - 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 = shortcuts)) { - shortcuts = shortcuts->next; - destroy_shortcut(s, 1); - } - shortcuts = nil; - - if(grabkb) { - XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, - CurrentTime); - return; + size_t i; + for(i = 0; i < nshortcut; i++) { + Shortcut *s = shortcut[i]; + if((s->mod == mod) && (s->key == key)) { + if(s->next) { + XGrabKeyboard(dpy, w, True, GrabModeAsync, GrabModeAsync, CurrentTime); + XMapRaised(dpy, win); + XSync(dpy, False); + + handle_shortcut_chain(w, s, s->name); + + XUngrabKeyboard(dpy, CurrentTime); + XUnmapWindow(dpy, win); + XSync(dpy, False); + } + else if(s->cmd) + wmii_spawn(dpy, s->cmd); + 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_shortcut_box(char *prefix) { - Draw d = { 0 }; - - d.font = font; - krect.width = XTextWidth(d.font, text, strlen(text)) + krect.height; - krect.height = font->ascent + font->descent + 4; + if(!strlen(box.data)) + return; + box.rect.x = box.rect.y = 0; + box.rect.height = box.font->ascent + box.font->descent + 4; + box.rect.width = XTextWidth(box.font, prefix, strlen(prefix)) + box.rect.height; + box.data = prefix; 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, files[K_BG_COLOR]->content); - d.fg = blitz_loadcolor(dpy, screen, files[K_FG_COLOR]->content); - d.border = - blitz_loadcolor(dpy, screen, files[K_BORDER_COLOR]->content); - blitz_drawlabel(dpy, &d); + blitz_drawlabel(dpy, &box); } static void -check_event(Connection * c) +check_event(IXPConn *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); + handle_shortcut_gkb(root, ev.xkey.state, (KeyCode) ev.xkey.keycode); else - handle_shortcut(root, ev.xkey.state, - (KeyCode) ev.xkey.keycode); + handle_shortcut(root, ev.xkey.state, (KeyCode) ev.xkey.keycode); break; case KeymapNotify: - update(); + { + size_t i; + for(i = 0; i < nshortcut; i++) { + ungrab_shortcut(shortcut[i]); + grab_shortcut(shortcut[i]); + } + } break; default: break; @@ -359,52 +313,596 @@ check_event(Connection * c) } } -static void -handle_after_write(IXPServer * s, File * f) +static int +dummy_error_handler(Display * dpy, XErrorEvent * err) { - 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); + return 0; } static int -dummy_error_handler(Display * dpy, XErrorEvent * err) +index_of_id(unsigned short id) +{ + int i; + for(i = 0; i < nitem; i++) + if(item[i]->id == id) + return i; + return -1; +} + +/* IXP stuff */ + +static unsigned long long +mkqpath(unsigned char type, unsigned short id) +{ + return ((unsigned long long) id << 8) | (unsigned long long) type; +} + +static unsigned char +qpath_type(unsigned long long path) +{ + return path & 0xff; +} + +static unsigned short +qpath_id(unsigned long long path) { + return (path >> 8) & 0xffff; +} + +static char * +qid_to_name(Qid *qid) +{ + unsigned char type = qpath_type(qid->path); + unsigned short id = qpath_id(qid->path); + int i; + static char buf[32]; + + if(id && ((i = index_of_id(id)) == -1)) + return nil; + switch(type) { + case Droot: return "/"; break; + case Ditem: + snprintf(buf, sizeof(buf), "%u", i + 1); + return buf; + break; + case Fctl: return "ctl"; break; + case Ffont: return "font"; break; + case Fdefcolor: return "defcolor"; break; + case Fexpand: return "expand"; break; + case Fdata: return "data"; break; + case Fevent: return "event"; break; + case Fcolor: return "color"; break; + default: return nil; break; + } +} + +static int +name_to_type(char *name) +{ + const char *err; + unsigned int i; + if(!name || !name[0] || !strncmp(name, "/", 2) || !strncmp(name, "..", 3)) + return Droot; + if(!strncmp(name, "new", 4)) + return Ditem; + if(!strncmp(name, "ctl", 4)) + return Fctl; + if(!strncmp(name, "font", 5)) + return Ffont; + if(!strncmp(name, "defcolor", 9)) + return Fdefcolor; + if(!strncmp(name, "expand", 7)) + return Fexpand; + if(!strncmp(name, "data", 5)) + return Fdata; + if(!strncmp(name, "event", 6)) + return Fevent; + if(!strncmp(name, "color", 6)) + return Fcolor; + i = (unsigned short) cext_strtonum(name, 1, 0xffff, &err); + if(!err && (i - 1 <= nitem)) + return Ditem; + return -1; +} + +static int +mkqid(Qid *dir, char *wname, Qid *new, Bool iswalk) +{ + const char *err; + unsigned short id = qpath_id(dir->path); + int i, type = name_to_type(wname); + + if(id && ((i = index_of_id(id)) == -1)) + return -1; + + if((dir->type != IXP_QTDIR) || (type == -1)) + return -1; + + new->dtype = qpath_type(dir->path); + new->version = 0; + switch(type) { + case Droot: + *new = root_qid; + break; + case Ditem: + new->type = IXP_QTDIR; + if(!strncmp(wname, "new", 4)) { + /*fprintf(stderr, "mkqid iswalk=%d, wname=%s\n", iswalk, wname);*/ + if(iswalk) + new->path = mkqpath(Ditem, new_item()->id); + else + new->path = mkqpath(Ditem, 0); + } + else { + i = cext_strtonum(wname, 1, 0xffff, &err); + if(err || (i - 1 >= nitem)) + return -1; + new->path = mkqpath(Ditem, item[i - 1]->id); + } + break; + case Fdata: + case Fcolor: + if(i >= nitem) + return -1; + default: + new->type = IXP_QTFILE; + new->path = mkqpath(type, id); + break; + } return 0; } + +static char * +xversion(IXPConn *c, Fcall *fcall) +{ + if(strncmp(fcall->version, IXP_VERSION, strlen(IXP_VERSION))) + return E9pversion; + else if(fcall->maxmsg > IXP_MAX_MSG) + fcall->maxmsg = IXP_MAX_MSG; + fcall->id = RVERSION; + ixp_server_respond_fcall(c, fcall); + return nil; +} + +static char * +xattach(IXPConn *c, Fcall *fcall) +{ + IXPMap *new = cext_emallocz(sizeof(IXPMap)); + new->qid = root_qid; + new->fid = fcall->fid; + c->map = (IXPMap **)cext_array_attach((void **)c->map, new, + sizeof(IXPMap *), &c->mapsz); + fcall->id = RATTACH; + fcall->qid = root_qid; + ixp_server_respond_fcall(c, fcall); + return nil; +} + +static char * +xwalk(IXPConn *c, Fcall *fcall) +{ + unsigned short nwqid = 0; + Qid dir = root_qid; + IXPMap *m; + + if(!(m = ixp_server_fid2map(c, fcall->fid))) + return Enofid; + if(fcall->fid != fcall->newfid && (ixp_server_fid2map(c, fcall->newfid))) + return Enofid; + if(fcall->nwname) { + dir = m->qid; + for(nwqid = 0; (nwqid < fcall->nwname) + && !mkqid(&dir, fcall->wname[nwqid], &fcall->wqid[nwqid], True); nwqid++) { + /*fprintf(stderr, "wname=%s nwqid=%d\n", fcall->wname[nwqid], nwqid);*/ + dir = fcall->wqid[nwqid]; + } + if(!nwqid) + return Enofile; + } + /* a fid will only be valid, if the walk was complete */ + if(nwqid == fcall->nwname) { + if(fcall->fid != fcall->newfid) { + m = cext_emallocz(sizeof(IXPMap)); + c->map = (IXPMap **)cext_array_attach((void **)c->map, + m, sizeof(IXPMap *), &c->mapsz); + } + m->qid = dir; + m->fid = fcall->newfid; + } + fcall->id = RWALK; + fcall->nwqid = nwqid; + ixp_server_respond_fcall(c, fcall); + return nil; +} + +static char * +xopen(IXPConn *c, Fcall *fcall) +{ + IXPMap *m = ixp_server_fid2map(c, fcall->fid); + + if(!m) + return Enofid; + if(!(fcall->mode | IXP_OREAD) && !(fcall->mode | IXP_OWRITE)) + return Enomode; + fcall->id = ROPEN; + fcall->qid = m->qid; + fcall->iounit = 256; + ixp_server_respond_fcall(c, fcall); + return nil; +} + +static unsigned int +mkstat(Stat *stat, Qid *dir, char *name, unsigned long long length, unsigned int mode) +{ + stat->mode = mode; + 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)); + + cext_strlcpy(stat->name, name, sizeof(stat->name)); + stat->length = length; + mkqid(dir, name, &stat->qid, False); + return ixp_sizeof_stat(stat); +} + +static unsigned int +type_to_stat(Stat *stat, char *name, Qid *dir) +{ + int i, type = name_to_type(name); + unsigned short id = qpath_id(dir->path); + char buf[16]; + + if(id && ((i = index_of_id(id)) == -1)) + return 0; + switch (type) { + case Droot: + case Ditem: + return mkstat(stat, dir, name, 0, DMDIR | DMREAD | DMEXEC); + break; + case Fctl: + return mkstat(stat, dir, name, 0, DMWRITE); + break; + case Fevent: + return mkstat(stat, dir, name, 0, DMREAD); + break; + case Ffont: + return mkstat(stat, dir, name, strlen(font), DMREAD | DMWRITE); + break; + case Fdefcolor: + return mkstat(stat, dir, name, 23, DMREAD | DMWRITE); + break; + case Fexpand: + snprintf(buf, sizeof(buf), "%u", iexpand + 1); + return mkstat(stat, dir, name, strlen(buf), DMREAD | DMWRITE); + break; + case Fdata: + return mkstat(stat, dir, name, (i == nitem) ? 0 : strlen(item[i]->data), DMREAD | DMWRITE); + break; + case Fcolor: + return mkstat(stat, dir, name, 23, DMREAD | DMWRITE); + break; + } + return 0; +} + +static char * +xremove(IXPConn *c, Fcall *fcall) +{ + IXPMap *m = ixp_server_fid2map(c, fcall->fid); + unsigned short id = qpath_id(m->qid.path); + int i; + + if(!m) + return Enofid; + if(id && ((i = qpath_id(id)) == -1)) + return Enofile; + if((qpath_type(m->qid.path) == Ditem) && i && (i < nitem)) { + Item *it = item[i]; + /* clunk */ + cext_array_detach((void **)c->map, m, &c->mapsz); + free(m); + /* now detach the item */ + detach_item(it); + free(it); + if(iexpand >= nitem) + iexpand = 0; + draw(); + fcall->id = RREMOVE; + ixp_server_respond_fcall(c, fcall); + return nil; + } + return Enoperm; +} + +static char * +xread(IXPConn *c, Fcall *fcall) +{ + Stat stat; + IXPMap *m = ixp_server_fid2map(c, fcall->fid); + unsigned short id; + unsigned char *p = fcall->data; + unsigned int len; + int i; + char buf[32]; + + if(!m) + return Enofid; + id = qpath_id(m->qid.path); + if(id && ((i = index_of_id(id)) == -1)) + return Enofile; + + fcall->count = 0; + if(fcall->offset) { + switch (qpath_type(m->qid.path)) { + case Droot: + /* jump to offset */ + len = type_to_stat(&stat, "ctl", &m->qid); + len += type_to_stat(&stat, "font", &m->qid); + len += type_to_stat(&stat, "defcolor", &m->qid); + len += type_to_stat(&stat, "expand", &m->qid); + len += type_to_stat(&stat, "new", &m->qid); + len += type_to_stat(&stat, "event", &m->qid); + for(i = 0; i < nitem; i++) { + snprintf(buf, sizeof(buf), "%u", i + 1); + len += type_to_stat(&stat, buf, &m->qid); + if(len <= fcall->offset) + continue; + break; + } + /* offset found, proceeding */ + for(; i < nitem; i++) { + snprintf(buf, sizeof(buf), "%u", i + 1); + len = type_to_stat(&stat, buf, &m->qid); + if(fcall->count + len > fcall->iounit) + break; + fcall->count += len; + p = ixp_enc_stat(p, &stat); + } + break; + case Fevent: + ixp_server_enqueue_fcall(c, fcall); + return nil; + break; + default: + break; + } + } + else { + switch (qpath_type(m->qid.path)) { + case Droot: + fcall->count = type_to_stat(&stat, "ctl", &m->qid); + p = ixp_enc_stat(p, &stat); + fcall->count += type_to_stat(&stat, "font", &m->qid); + p = ixp_enc_stat(p, &stat); + fcall->count += type_to_stat(&stat, "defcolor", &m->qid); + p = ixp_enc_stat(p, &stat); + fcall->count += type_to_stat(&stat, "expand", &m->qid); + p = ixp_enc_stat(p, &stat); + fcall->count += type_to_stat(&stat, "new", &m->qid); + p = ixp_enc_stat(p, &stat); + fcall->count += type_to_stat(&stat, "event", &m->qid); + p = ixp_enc_stat(p, &stat); + for(i = 0; i < nitem; i++) { + snprintf(buf, sizeof(buf), "%u", i + 1); + len = type_to_stat(&stat, buf, &m->qid); + if(fcall->count + len > fcall->iounit) + break; + fcall->count += len; + p = ixp_enc_stat(p, &stat); + } + break; + case Ditem: + if(i >= nitem) + return Enofile; + fcall->count = type_to_stat(&stat, "color", &m->qid); + p = ixp_enc_stat(p, &stat); + fcall->count += type_to_stat(&stat, "data", &m->qid); + p = ixp_enc_stat(p, &stat); + break; + case Fctl: + return Enoperm; + break; + case Ffont: + if((fcall->count = strlen(font))) + memcpy(p, font, fcall->count); + break; + case Fdefcolor: + if((fcall->count = strlen(defcolstr))) + memcpy(p, defcolstr, fcall->count); + break; + case Fexpand: + snprintf(buf, sizeof(buf), "%u", iexpand + 1); + fcall->count = strlen(buf); + memcpy(p, buf, fcall->count); + break; + case Fdata: + if(i >= nitem) + return Enofile; + if((fcall->count = strlen(item[i]->data))) + memcpy(p, item[i]->data, fcall->count); + break; + case Fcolor: + if(i >= nitem) + return Enofile; + if((fcall->count = strlen(item[i]->colstr))) + memcpy(p, item[i]->colstr, fcall->count); + break; + case Fevent: + ixp_server_enqueue_fcall(c, fcall); + return nil; + break; + default: + return "invalid read"; + break; + } + } + fcall->id = RREAD; + ixp_server_respond_fcall(c, fcall); + return nil; +} + +static char * +xstat(IXPConn *c, Fcall *fcall) +{ + IXPMap *m = ixp_server_fid2map(c, fcall->fid); + char *name; + + if(!m) + return Enofid; + name = qid_to_name(&m->qid); + /*fprintf(stderr, "xstat: name=%s\n", name);*/ + if(!type_to_stat(&fcall->stat, name, &m->qid)) + return Enofile; + fcall->id = RSTAT; + ixp_server_respond_fcall(c, fcall); + return nil; +} + +static char * +xwrite(IXPConn *c, Fcall *fcall) +{ + char buf[256]; + IXPMap *m = ixp_server_fid2map(c, fcall->fid); + unsigned short id; + int i; + + if(!m) + return Enofid; + id = qpath_id(m->qid.path); + if(id && ((i = index_of_id(id)) == -1)) + return Enofile; + switch (qpath_type(m->qid.path)) { + case Fctl: + if(fcall->count == 4) { + memcpy(buf, fcall->data, 4); + buf[4] = 0; + if(!strncmp(buf, "quit", 5)) { + srv.running = 0; + break; + } + } + return Enocommand; + break; + case Ffont: + if(font) + free(font); + font = cext_emallocz(fcall->count + 1); + memcpy(font, fcall->data, fcall->count); + XFreeFont(dpy, xfont); + xfont = blitz_getfont(dpy, font); + update_geometry(); + break; + case Fdefcolor: + if((fcall->count != 23) + || (fcall->data[0] != '#') || (fcall->data[8] != '#') + || (fcall->data[16] != '#') + ) + return "wrong color format"; + memcpy(defcolstr, fcall->data, fcall->count); + defcolstr[fcall->count] = 0; + blitz_loadcolor(dpy, screen, defcolstr, &defcolor); + break; + case Fexpand: + { + const char *err; + if(fcall->count && fcall->count < 16) { + memcpy(buf, fcall->data, fcall->count); + buf[fcall->count] = 0; + i = (unsigned short) cext_strtonum(buf, 1, 0xffff, &err); + if(!err && (i - 1 < nitem)) { + iexpand = i - 1; + draw(); + break; + } + } + } + return Enofile; + break; + case Fdata: + { + unsigned int len = fcall->count; + if(i >= nitem) + return Enofile; + if(len >= sizeof(item[i]->data)) + len = sizeof(item[i]->data) - 1; + memcpy(item[i]->data, fcall->data, len); + item[i]->data[len] = 0; + draw(); + } + break; + case Fcolor: + if((i >= nitem) || (fcall->count != 23) + || (fcall->data[0] != '#') || (fcall->data[8] != '#') + || (fcall->data[16] != '#') + ) + return "wrong color format"; + memcpy(item[i]->colstr, fcall->data, fcall->count); + item[i]->colstr[fcall->count] = 0; + blitz_loadcolor(dpy, screen, item[i]->colstr, &item[i]->color); + draw(); + break; + default: + return "invalid write"; + break; + } + fcall->id = RWRITE; + ixp_server_respond_fcall(c, fcall); + return nil; +} + +static char * +xclunk(IXPConn *c, Fcall *fcall) +{ + IXPMap *m = ixp_server_fid2map(c, fcall->fid); + + if(!m) + return Enofid; + cext_array_detach((void **)c->map, m, &c->mapsz); + free(m); + fcall->id = RCLUNK; + ixp_server_respond_fcall(c, fcall); + return nil; +} + +static void +do_fcall(IXPConn *c) +{ + static Fcall fcall; + unsigned int msize; + char *errstr; + + if((msize = ixp_server_receive_fcall(c, &fcall))) { + /*fprintf(stderr, "fcall=%d\n", fcall.id);*/ + switch(fcall.id) { + case TVERSION: errstr = xversion(c, &fcall); break; + case TATTACH: errstr = xattach(c, &fcall); break; + case TWALK: errstr = xwalk(c, &fcall); break; + case TREMOVE: errstr = xremove(c, &fcall); break; + case TOPEN: errstr = xopen(c, &fcall); break; + case TREAD: errstr = xread(c, &fcall); break; + case TWRITE: errstr = xwrite(c, &fcall); break; + case TCLUNK: errstr = xclunk(c, &fcall); break; + case TSTAT: errstr = xstat(c, &fcall); break; + default: errstr = Enofunc; break; + } + if(errstr) + ixp_server_respond_error(c, &fcall, errstr); + } +} + +static void +new_ixp_conn(IXPConn *c) +{ + int fd = ixp_accept_sock(c->fd); + + if(fd >= 0) + ixp_server_open_conn(c->srv, fd, do_fcall, ixp_server_close_conn); +} + +/* main */ + int main(int argc, char *argv[]) {