#include #include #include #include #include enum { Kbdmsgsz = 1 + 4 /* allow for 32-bit runes */ }; typedef struct Slave Slave; typedef struct Ebuf Ebuf; struct Slave { int pid; Ebuf *head; /* queue of messages for this descriptor */ Ebuf *tail; int (*fn)(int, Event*, uchar*, int); }; struct Ebuf { Ebuf *next; int n; /* number of bytes in buf */ uchar buf[EMAXMSG]; }; static Slave eslave[MAXSLAVE]; static int Skeyboard = -1; static int Smouse = -1; static int Stimer = -1; static int logfid; static int nslave; static int parentpid; static int epipe[2]; static int eforkslave(ulong); static void extract(void); static void ekill(void); static int enote(void *, char *); static int mousefd; static int cursorfd; static Ebuf* ebread(Slave *s) { Ebuf *eb; Dir *d; ulong l; for(;;){ d = dirfstat(epipe[0]); if(d == nil) drawerror(display, "events: eread stat error"); l = d->length; free(d); if(s->head && l==0) break; extract(); } eb = s->head; s->head = s->head->next; if(s->head == 0) s->tail = 0; return eb; } ulong event(Event *e) { return eread(~0UL, e); } ulong eread(ulong keys, Event *e) { Ebuf *eb; int i, id; if(keys == 0) return 0; for(;;){ for(i=0; imouse = emouse(); else if(i == Skeyboard) e->kbdc = ekbd(); else if(i == Stimer) eslave[i].head = 0; else{ eb = ebread(&eslave[i]); e->n = eb->n; if(eslave[i].fn) id = (*eslave[i].fn)(id, e, eb->buf, eb->n); else memmove(e->data, eb->buf, eb->n); free(eb); } return id; } extract(); } } int ecanmouse(void) { if(Smouse < 0) drawerror(display, "events: mouse not initialized"); return ecanread(Emouse); } int ecankbd(void) { if(Skeyboard < 0) drawerror(display, "events: keyboard not initialzed"); return ecanread(Ekeyboard); } int ecanread(ulong keys) { Dir *d; int i; ulong l; for(;;){ for(i=0; ilength; free(d); if(l == 0) return 0; extract(); } } ulong estartfn(ulong key, int fd, int n, int (*fn)(int, Event*, uchar*, int)) { char buf[EMAXMSG+1]; int i, r; if(fd < 0) drawerror(display, "events: bad file descriptor"); if(n <= 0 || n > EMAXMSG) n = EMAXMSG; i = eforkslave(key); if(i < MAXSLAVE){ eslave[i].fn = fn; return 1<0) if(write(epipe[1], buf, r+1)!=r+1) break; buf[0] = MAXSLAVE; write(epipe[1], buf, 1); _exits(0); return 0; } ulong estart(ulong key, int fd, int n) { return estartfn(key, fd, n, nil); } ulong etimer(ulong key, int n) { char t[2]; if(Stimer != -1) drawerror(display, "events: timer started twice"); Stimer = eforkslave(key); if(Stimer < MAXSLAVE) return 1<>8; t[3] = r>>16; t[4] = r>>24; if(write(epipe[1], t, sizeof t) != sizeof t) break; } breakout:; t[0] = MAXSLAVE; write(epipe[1], t, 1); _exits(0); } void einit(ulong keys) { int ctl, fd; char buf[256]; parentpid = getpid(); if(pipe(epipe) < 0) drawerror(display, "events: einit pipe"); atexit(ekill); atnotify(enote, 1); snprint(buf, sizeof buf, "%s/mouse", display->devdir); mousefd = open(buf, ORDWR|OCEXEC); if(mousefd < 0) drawerror(display, "einit: can't open mouse\n"); snprint(buf, sizeof buf, "%s/cursor", display->devdir); cursorfd = open(buf, ORDWR|OCEXEC); if(cursorfd < 0) drawerror(display, "einit: can't open cursor\n"); if(keys&Ekeyboard){ snprint(buf, sizeof buf, "%s/cons", display->devdir); fd = open(buf, OREAD); if(fd < 0) drawerror(display, "events: can't open console"); snprint(buf, sizeof buf, "%s/consctl", display->devdir); ctl = open("/dev/consctl", OWRITE|OCEXEC); if(ctl < 0) drawerror(display, "events: can't open consctl"); write(ctl, "rawon", 5); for(Skeyboard=0; Ekeyboard & ~(1<locking){ /* if locking is being done by program, this means it can't depend on automatic flush in emouse() etc. */ if(canqlock(&display->qlock)){ if(display->bufp > display->buf) flushimage(display, 1); unlockdisplay(display); } }else if(display->bufp > display->buf) flushimage(display, 1); loop: if((n=read(epipe[0], ebuf, EMAXMSG+1)) < 0 || ebuf[0] >= MAXSLAVE) drawerror(display, "eof on event pipe"); if(n == 0) goto loop; i = ebuf[0]; if(i >= nslave || n <= 1) drawerror(display, "events: protocol error: short read"); s = &eslave[i]; if(i == Stimer){ s->head = (Ebuf *)1; return; } if(i == Skeyboard && n != Kbdmsgsz) drawerror(display, "events: protocol error: keyboard"); if(i == Smouse){ if(n < 1+1+2*12) drawerror(display, "events: protocol error: mouse"); if(ebuf[1] == 'r') eresized(1); /* squash extraneous mouse events */ if((eb=s->tail) && memcmp(eb->buf+1+2*12, ebuf+1+1+2*12, 12)==0){ memmove(eb->buf, &ebuf[1], n - 1); return; } } /* try to save space by only allocating as much buffer as we need */ eb = malloc(sizeof(*eb) - sizeof(eb->buf) + n - 1); if(eb == 0) drawerror(display, "events: protocol error 4"); eb->n = n - 1; memmove(eb->buf, &ebuf[1], n - 1); eb->next = 0; if(s->head) s->tail = s->tail->next = eb; else s->head = s->tail = eb; } static int eforkslave(ulong key) { int i, pid; for(i=0; ibuf+1+0*12); m.xy.y = atoi((char*)eb->buf+1+1*12); b = atoi((char*)eb->buf+1+2*12); m.buttons = b; m.msec = atoi((char*)eb->buf+1+3*12); if (logfid) fprint(logfid, "b: %d xy: %P\n", m.buttons, m.xy); free(eb); return m; } int ekbd(void) { uchar *t; int c; Ebuf *eb; if(Skeyboard < 0) drawerror(display, "events: keyboard not initialzed"); eb = ebread(&eslave[Skeyboard]); t = eb->buf; c = t[0] | t[1]<<8 | t[2]<<16 | t[3]<<24; free(eb); return c; } void emoveto(Point pt) { char buf[2*12+2]; int n; n = sprint(buf, "m%d %d", pt.x, pt.y); write(mousefd, buf, n); } void esetcursor(Cursor *c) { uchar curs[2*4+2*2*16]; if(c == 0) write(cursorfd, curs, 0); else{ BPLONG(curs+0*4, c->offset.x); BPLONG(curs+1*4, c->offset.y); memmove(curs+2*4, c->clr, 2*2*16); write(cursorfd, curs, sizeof curs); } } int ereadmouse(Mouse *m) { int n; char buf[128]; do{ n = read(mousefd, buf, sizeof(buf)); if(n < 0) /* probably interrupted */ return -1; n = eatomouse(m, buf, n); }while(n == 0); return n; } int eatomouse(Mouse *m, char *buf, int n) { if(n != 1+4*12){ werrstr("atomouse: bad count"); return -1; } if(buf[0] == 'r') eresized(1); m->xy.x = atoi(buf+1+0*12); m->xy.y = atoi(buf+1+1*12); m->buttons = atoi(buf+1+2*12); m->msec = atoi(buf+1+3*12); return n; }