void writecolmap(Display *d, RGB *m) { int i, n, fd; char buf[64], *t; ulong r, g, b; sprint(buf, "/dev/draw/%d/colormap", d->dirno); fd = open(buf, OWRITE); if(fd < 0) drawerror(d, "writecolmap: open colormap failed"); t = malloc(8192); if (t == nil) drawerror(d, "writecolmap: no memory"); n = 0; for(i = 0; i < 256; i++) { r = m[i].red>>24; g = m[i].green>>24; b = m[i].blue>>24; n += sprint(t+n, "%d %lud %lud %lud\n", 255-i, r, g, b); } i = write(fd, t, n); free(t); close(fd); if(i != n) drawerror(d, "writecolmap: bad write"); }
int _frcanfit(Frame *f, Point pt, Frbox *b) { int left, w, nr; uchar *p; Rune r; left = f->r.max.x-pt.x; if(b->nrune < 0) return b->minwid <= left; if(left >= b->wid) return b->nrune; for(nr=0,p=b->ptr; *p; p+=w,nr++){ r = *p; if(r < Runeself) w = 1; else w = chartorune(&r, (char*)p); left -= stringnwidth(f->font, (char*)p, 1); if(left < 0) return nr; } drawerror(f->display, "_frcanfit can't"); return 0; }
int ecanmouse(void) { if(Smouse < 0) drawerror(display, "events: mouse not initialized"); return ecanread(Emouse); }
static int eforkslave(ulong key) { int i, pid; for(i=0; i<MAXSLAVE; i++) if((key & ~(1<<i)) == 0 && eslave[i].pid == 0){ if(nslave <= i) nslave = i + 1; /* * share the file descriptors so the last child * out closes all connections to the window server. */ switch(pid = rfork(RFPROC)){ case 0: return MAXSLAVE+i; case -1: fprint(2, "events: fork error\n"); exits("fork"); } eslave[i].pid = pid; eslave[i].head = eslave[i].tail = 0; return i; } drawerror(display, "events: bad slave assignment"); return 0; }
Point _frdraw(Frame *f, Point pt) { Frbox *b; int nb, n; for(b=f->box,nb=0; nb<f->nbox; nb++, b++) { _frcklinewrap0(f, &pt, b); if(pt.y == f->r.max.y) { f->nchars -= _frstrlen(f, nb); _frdelbox(f, nb, f->nbox-1); break; } if(b->nrune > 0) { n = _frcanfit(f, pt, b); if(n == 0) drawerror(f->display, "_frcanfit==0"); if(n != b->nrune) { _frsplitbox(f, nb, n); b = &f->box[nb]; } pt.x += b->wid; } else { if(b->bc == '\n') { pt.x = f->r.min.x; pt.y+=f->font->height; } else pt.x += _frnewwid(f, pt, b); } } return pt; }
Mouse emouse(void) { Mouse m; Ebuf *eb; static but[2]; int b; if(Smouse < 0) drawerror(display, "events: mouse not initialized"); for(;;){ eb = ebread(&eslave[Smouse]); if(!ecanmouse()) break; free(eb); /* drop queued mouse events */ } m.xy.x = atoi((char*)eb->buf+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 ecankbd(void) { if(Skeyboard < 0) drawerror(display, "events: keyboard not initialzed"); return ecanread(Ekeyboard); }
ulong etimer(ulong key, int n) { if(Stimer != -1) drawerror(display, "events: timer started twice"); Stimer = newkey(key); if(n <= 0) n = 1000; eslave[Stimer].n = n; eslave[Stimer].nexttick = nsec()+n*1000000LL; return 1<<Stimer; }
int ekbd(void) { Ebuf *eb; int c; if(Skeyboard < 0) drawerror(display, "events: keyboard not initialzed"); eb = ebread(&eslave[Skeyboard]); c = eb->u.rune; free(eb); return c; }
Mouse emouse(void) { Mouse m; Ebuf *eb; if(Smouse < 0) drawerror(display, "events: mouse not initialized"); eb = ebread(&eslave[Smouse]); m = eb->u.mouse; free(eb); return m; }
int ekbd(void) { Ebuf *eb; Rune r; if(Skeyboard < 0) drawerror(display, "events: keyboard not initialzed"); eb = ebread(&eslave[Skeyboard]); chartorune(&r, (char*)eb->buf); free(eb); return r; }
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<<Skeyboard); Skeyboard++) ; ekeyslave(fd); } if(keys&Emouse){ estart(Emouse, mousefd, 1+4*12); for(Smouse=0; Emouse & ~(1<<Smouse); Smouse++) ; } }
static int newkey(ulong key) { int i; for(i=0; i<MAXSLAVE; i++) if((key & ~(1<<i)) == 0 && eslave[i].inuse == 0){ if(nslave <= i) nslave = i + 1; eslave[i].inuse = 1; return i; } drawerror(display, "events: bad slave assignment"); return 0; }
ulong estartfn(ulong key, int fd, int n, int (*fn)(int, Event*, uchar*, int)) { int i; if(fd < 0) drawerror(display, "events: bad file descriptor"); if(n <= 0 || n > EMAXMSG) n = EMAXMSG; i = newkey(key); eslave[i].fn = fn; eslave[i].fd = fd; eslave[i].n = n; return 1<<i; }
static Ebuf* newebuf(Slave *s, int n) { Ebuf *eb; eb = malloc(sizeof(*eb) - sizeof(eb->u.buf) + n); if(eb == nil) drawerror(display, "events: out of memory"); eb->n = n; eb->next = 0; if(s->head) s->tail = s->tail->next = eb; else s->head = s->tail = eb; return eb; }
int ecanread(ulong keys) { Dir *d; int i; ulong l; for(;;){ for(i=0; i<nslave; i++) if((keys & (1<<i)) && eslave[i].head) return 1; d = dirfstat(epipe[0]); if(d == nil) drawerror(display, "events: ecanread stat error"); l = d->length; free(d); if(l == 0) return 0; extract(); } }
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<<Stimer; if(n <= 0) n = 1000; t[0] = t[1] = Stimer - MAXSLAVE; do sleep(n); while(write(epipe[1], t, 2) == 2); t[0] = MAXSLAVE; write(epipe[1], t, 1); _exits(0); return 0; }
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<<i; } buf[0] = i - MAXSLAVE; while((r = read(fd, buf+1, n))>0) if(write(epipe[1], buf, r+1)!=r+1) break; buf[0] = MAXSLAVE; write(epipe[1], buf, 1); _exits(0); return 0; }
static int extract(int canblock) { Ebuf *eb; int i, n, max; fd_set rset, wset, xset; struct timeval tv, *timeout; Wsysmsg w; vlong t0; /* * Flush draw buffer before waiting for responses. * Avoid doing so if buffer is empty. * Also make sure that we don't interfere with app-specific locking. */ if(display->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); /* * Set up for select. */ FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&xset); max = -1; timeout = nil; for(i=0; i<nslave; i++){ if(!eslave[i].inuse) continue; if(i == Smouse){ if(eslave[i].rpc == nil) eslave[i].rpc = startrpc(Trdmouse); if(eslave[i].rpc){ /* if ready, don't block in select */ if(eslave[i].rpc->p) canblock = 0; FD_SET(display->srvfd, &rset); FD_SET(display->srvfd, &xset); if(display->srvfd > max) max = display->srvfd; } }else if(i == Skeyboard){ if(eslave[i].rpc == nil) eslave[i].rpc = startrpc(Trdkbd); if(eslave[i].rpc){ /* if ready, don't block in select */ if(eslave[i].rpc->p) canblock = 0; FD_SET(display->srvfd, &rset); FD_SET(display->srvfd, &xset); if(display->srvfd > max) max = display->srvfd; } }else if(i == Stimer){ t0 = nsec(); if(t0 >= eslave[i].nexttick){ tv.tv_sec = 0; tv.tv_usec = 0; }else{ tv.tv_sec = (eslave[i].nexttick-t0)/1000000000; tv.tv_usec = (eslave[i].nexttick-t0)%1000000000 / 1000; } timeout = &tv; }else{ FD_SET(eslave[i].fd, &rset); FD_SET(eslave[i].fd, &xset); if(eslave[i].fd > max) max = eslave[i].fd; } } if(!canblock){ tv.tv_sec = 0; tv.tv_usec = 0; timeout = &tv; } if(select(max+1, &rset, &wset, &xset, timeout) < 0) drawerror(display, "select failure"); /* * Look to see what can proceed. */ n = 0; for(i=0; i<nslave; i++){ if(!eslave[i].inuse) continue; if(i == Smouse){ if(finishrpc(eslave[i].rpc, &w)){ eslave[i].rpc = nil; eb = newebuf(&eslave[i], sizeof(Mouse)); _drawmouse = w.mouse; eb->u.mouse = w.mouse; if(w.resized) eresized(1); n++; } }else if(i == Skeyboard){ if(finishrpc(eslave[i].rpc, &w)){ eslave[i].rpc = nil; eb = newebuf(&eslave[i], sizeof(Rune)+2); /* +8: alignment */ eb->u.rune = w.rune; n++; } }else if(i == Stimer){ t0 = nsec(); while(t0 > eslave[i].nexttick){ eslave[i].nexttick += eslave[i].n*1000000LL; eslave[i].head = (Ebuf*)1; n++; } }else{ if(FD_ISSET(eslave[i].fd, &rset)){ eb = newebuf(&eslave[i], eslave[i].n); eb->n = read(eslave[i].fd, eb->u.buf, eslave[i].n); n++; } } } return n; }
static void extract(void) { Slave *s; Ebuf *eb; int i, n; uchar ebuf[EMAXMSG+1]; /* avoid generating a message if there's nothing to show. */ /* this test isn't perfect, though; could do flushimage(display, 0) then call extract */ /* also: make sure we don't interfere if we're multiprocessing the display */ if(display->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 != (1+UTFmax)) 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->next = eb; else s->head = eb; s->tail = eb; }