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:
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[])
{