void keyboardthread(void *) { Rune r; Timer *timer; Text *t; enum { KTimer, KKey, NKALT }; static Alt alts[NKALT+1]; alts[KTimer].c = nil; alts[KTimer].v = nil; alts[KTimer].op = CHANNOP; alts[KKey].c = keyboardctl->c; alts[KKey].v = &r; alts[KKey].op = CHANRCV; alts[NKALT].op = CHANEND; timer = nil; typetext = nil; threadsetname("keyboardthread"); for(;;){ switch(alt(alts)){ case KTimer: timerstop(timer); t = typetext; if(t!=nil && t->what==Tag){ winlock(t->w, 'K'); wincommit(t->w, t); winunlock(t->w); flushimage(display, 1); } alts[KTimer].c = nil; alts[KTimer].op = CHANNOP; break; case KKey: casekeyboard: typetext = rowtype(&row, r, mouse->xy); t = typetext; if(t!=nil && t->col!=nil && !(r==Kdown || r==Kleft || r==Kright)) /* scrolling doesn't change activecol */ activecol = t->col; if(t!=nil && t->w!=nil) t->w->body.file->curtext = &t->w->body; if(timer != nil) timercancel(timer); if(t!=nil && t->what==Tag) { timer = timerstart(500); alts[KTimer].c = timer->c; alts[KTimer].op = CHANRCV; }else{ timer = nil; alts[KTimer].c = nil; alts[KTimer].op = CHANNOP; } if(nbrecv(keyboardctl->c, &r) > 0) goto casekeyboard; flushimage(display, 1); break; } } }
int unloadimage(Image *i, Rectangle r, uchar *data, int ndata) { int bpl, n, chunk, dx, dy; uchar *a, *start; Display *d; if(!rectinrect(r, i->r)) { werrstr("unloadimage: bad rectangle"); return -1; } bpl = bytesperline(r, i->depth); if(ndata < bpl*Dy(r)) { werrstr("unloadimage: buffer too small"); return -1; } start = data; d = i->display; chunk = d->bufsize; flushimage(d, 0); /* make sure subsequent flush is for us only */ while(r.min.y < r.max.y) { dx = Dx(r); dy = chunk/bpl; if(dy <= 0) { dy = 1; dx = ((chunk*dx)/bpl) & ~7; n = bytesperline(Rect(r.min.x, r.min.y, r.min.x+dx, r.min.y+dy), i->depth); if(unloadimage(i, Rect(r.min.x+dx, r.min.y, r.max.x, r.min.y+dy), data+n, bpl-n) < 0) return -1; } else { if(dy > Dy(r)) dy = Dy(r); n = bpl*dy; } a = bufimage(d, 1+4+4*4); if(a == nil) { werrstr("unloadimage: %r"); return -1; } a[0] = 'r'; BPLONG(a+1, i->id); BPLONG(a+5, r.min.x); BPLONG(a+9, r.min.y); BPLONG(a+13, r.min.x+dx); BPLONG(a+17, r.min.y+dy); if(flushimage(d, 0) < 0) return -1; if(read(d->fd, data, n) < 0) return -1; data += bpl*dy; r.min.y += dy; } return data - start; }
int horiz(void) { int lev[MAXN]; int i, j, h; Rectangle r; h = 0; for(i=0; i<NY; i++) { for(j=0; board[i][j]; j++) if(j == NX-1) { lev[h++] = i; break; } } if(h == 0) return 0; r = rboard; newscreen = 0; for(j=0; j<h; j++) { r.min.y = rboard.min.y + lev[j]*pcsz; r.max.y = r.min.y + pcsz; draw(screen, r, display->white, whitemask, ZP); flushimage(display, 1); } for(i=0; i<3; i++) { pause(250); if(newscreen) { drawboard(); break; } for(j=0; j<h; j++) { r.min.y = rboard.min.y + lev[j]*pcsz; r.max.y = r.min.y + pcsz; draw(screen, r, display->white, whitemask, ZP); } flushimage(display, 1); } r = rboard; for(j=0; j<h; j++) { i = NY - lev[j] - 1; score(250+10*i*i); r.min.y = rboard.min.y; r.max.y = rboard.min.y+lev[j]*pcsz; draw(screen, rectaddpt(r, Pt(0,pcsz)), screen, nil, r.min); r.max.y = rboard.min.y+pcsz; draw(screen, r, display->white, nil, ZP); memcpy(&board[1][0], &board[0][0], NX*lev[j]); memset(&board[0][0], 0, NX); } flushimage(display, 1); return 1; }
int unloadimage(Image *i, Rectangle r, uchar *data, int ndata) { int bpl, n, ntot, dy; uchar *a; Display *d; if(!rectinrect(r, i->r)){ werrstr("unloadimage: bad rectangle"); return -1; } bpl = bytesperline(r, i->depth); if(ndata < bpl*Dy(r)){ werrstr("unloadimage: buffer too small"); return -1; } d = i->display; flushimage(d, 0); /* make sure subsequent flush is for us only */ ntot = 0; while(r.min.y < r.max.y){ a = bufimage(d, 1+4+4*4); if(a == 0){ werrstr("unloadimage: %r"); return -1; } dy = 8000/bpl; if(dy <= 0){ werrstr("unloadimage: image too wide"); return -1; } if(dy > Dy(r)) dy = Dy(r); a[0] = 'r'; BPLONG(a+1, i->id); BPLONG(a+5, r.min.x); BPLONG(a+9, r.min.y); BPLONG(a+13, r.max.x); BPLONG(a+17, r.min.y+dy); if(flushimage(d, 0) < 0) return -1; n = read(d->fd, data+ntot, ndata-ntot); if(n < 0) return n; ntot += n; r.min.y += dy; } return ntot; }
void showpage(int page, Menu *m) { if(doc->fwdonly) m->lasthit = 0; /* this page */ else m->lasthit = reverse ? doc->npage-1-page : page; esetcursor(&reading); delayfreeimage(nil); im = cachedpage(doc, angle, page); if(im == nil) wexits(0); if(resizing) resize(Dx(im->r), Dy(im->r)); esetcursor(nil); if(showbottom){ ul.y = screen->r.max.y - Dy(im->r); showbottom = 0; } redraw(screen); flushimage(display, 1); }
char* tkupdate(TkTop *t) { Tk* tk; int locked; TkWin *tkw; Display *d; char *e; int dirty = 0; if(t->noupdate) return nil; d = t->display; locked = lockdisplay(d); tk = t->windows; while(tk) { tkw = TKobj(TkWin, tk); if((tk->flag & (Tkmapped|Tksuspended)) == Tkmapped) { if (tkupdatewinsize(tk) == 0){ e = tkdrawslaves(tk, ZP, &dirty); if(e != nil) return e; } } tk = tkw->next; } if (dirty || t->dirty) { flushimage(d, 1); t->dirty = 0; } if(locked) unlockdisplay(d); return nil; }
void done(void) { level.done = 1; draw(screen, screen->r, selected, gameover, ZP); flushimage(display, 1); }
Image * getcolor(int rgb) { Color *c; int h; if(rgb == 0xFFFFFF) return display->white; else if(rgb == 0x000000) return display->black; h = rgb%NHASH; for(c=colortab[h]; c!=nil; c=c->next) if(c->rgb == rgb) { flushimage(display, 0); /* BUG? */ return c->i; } c = emalloc(sizeof(Color)); c->i = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, (rgb<<8)|0xFF); c->rgb = rgb; c->next = colortab[h]; colortab[h] = c; return c->i; }
char *pan(void) { Point dd, xy, lastxy, min, max; esetcursor(&blot); waitdown(); xy = mouse.xy; do{ lastxy = mouse.xy; mouse = emouse(); dd = subpt(mouse.xy, lastxy); min = addpt(screen->clipr.min, dd); max = addpt(screen->clipr.max, dd); draw(screen, rectaddpt(screen->r, subpt(mouse.xy, lastxy)), screen, nil, screen->r.min); if(mouse.xy.x < lastxy.x) /* moved left, clear right */ draw(screen, Rect(max.x, screen->r.min.y, screen->r.max.x, screen->r.max.y), display->white, nil, ZP); else /* moved right, clear left*/ draw(screen, Rect(screen->r.min.x, screen->r.min.y, min.x, screen->r.max.y), display->white, nil, ZP); if(mouse.xy.y < lastxy.y) /* moved up, clear down */ draw(screen, Rect(screen->r.min.x, max.y, screen->r.max.x, screen->r.max.y), display->white, nil, ZP); else /* moved down, clear up */ draw(screen, Rect(screen->r.min.x, screen->r.min.y, screen->r.max.x, min.y), display->white, nil, ZP); flushimage(display, 1); }while(mouse.buttons); xyoffset = addpt(xyoffset, subpt(mouse.xy, xy)); esetcursor(0); return "p"; }
void rleft(void) { if(canfit(rotl(piece))) { setpiece(rotl(piece)); drawpiece(); flushimage(display, 1); } }
void redraw(Image *screen) { int i; draw(screen, screen->r, lightblue, nil, ZP); for(i=0; i<nmap; i++) drawmap(i); flushimage(display, 1); }
void mleft(void) { if(!collide(Pt(pos.x-pcsz, pos.y), piece)) if(!collide(Pt(pos.x-pcsz, pos.y+pcsz-DY), piece)) { undrawpiece(); pos.x -= pcsz; drawpiece(); flushimage(display, 1); } }
int readmouse(Mousectl *mc) { if(mc->image) flushimage(mc->image->display, 1); if(recv(mc->c, (Mouse *)mc) < 0){ fprint(2, "readmouse: %r\n"); return -1; } return 0; }
void drawbar(void) { int i, j; int p; char buf[400], bar[200]; static char lastbar[200]; if(n > d || n < 0 || d <= 0) return; i = (Dx(rbar)*n)/d; p = (n*100LL)/d; if(textmode){ if(Dx(rbar) > 150){ rbar.min.x = 0; rbar.max.x = 150; return; } bar[0] = '|'; for(j=0; j<i; j++) bar[j+1] = '#'; for(; j<Dx(rbar); j++) bar[j+1] = '-'; bar[j++] = '|'; bar[j++] = ' '; sprint(bar+j, "%3d%% ", p); for(i=0; bar[i]==lastbar[i] && bar[i]; i++) ; memset(buf, '\b', strlen(lastbar)-i); strcpy(buf+strlen(lastbar)-i, bar+i); if(buf[0]) write(1, buf, strlen(buf)); strcpy(lastbar, bar); return; } if(lastp == p && last == i) return; if(lastp != p){ sprint(buf, "%d%%", p); stringbg(screen, addpt(screen->r.min, Pt(Dx(rbar)-30, 4)), text, ZP, display->defaultfont, buf, light, ZP); lastp = p; } if(last != i){ draw(screen, Rect(rbar.min.x+last, rbar.min.y, rbar.min.x+i, rbar.max.y), dark, nil, ZP); last = i; } flushimage(display, 1); }
void keyboardthread(void *) { Timer *timer; Text *t; Rune r; static Alt alts[NKALT+1]; alts[KTimer].c = nil; alts[KTimer].v = nil; alts[KTimer].op = CHANNOP; alts[KKey].c = keyboardctl->c; alts[KKey].v = &r; alts[KKey].op = CHANRCV; alts[NKALT].op = CHANEND; timer = nil; threadsetname("keyboardthread"); for(;;){ switch(alt(alts)){ case KTimer: timerstop(timer); alts[KTimer].c = nil; alts[KTimer].op = CHANNOP; break; case KKey: casekeyboard: typetext = rowwhich(&row, mouse->xy, r, TRUE); t = typetext; if(t!=nil && t->col!=nil && !(r==Kdown || r==Kleft || r==Kright)) /* scrolling doesn't change activecol */ activecol = t->col; if(timer != nil) timercancel(timer); if(t!=nil){ texttype(t, r); timer = timerstart(500); alts[KTimer].c = timer->c; alts[KTimer].op = CHANRCV; }else{ timer = nil; alts[KTimer].c = nil; alts[KTimer].op = CHANNOP; } if(nbrecv(keyboardctl->c, &r) > 0) goto casekeyboard; flushimage(display, 1); break; } } }
void timeproc(void *dummy) { for(;;){ lockdisplay(display); drawtime(); updatetimes(); flushimage(display, 1); unlockdisplay(display); sleep(60000); setdate(); } }
void suspend(int s) { suspended = s; if (suspended) setcursor(mousectl, &whitearrow); else setcursor(mousectl, nil); if (!suspended) drawpiece(); drawboard(); flushimage(display, 1); }
/* * menur is a rectangle holding all the highlightable text elements. * track mouse while inside the box, return what's selected when button * is raised, -1 as soon as it leaves box. * invariant: nothing is highlighted on entry or exit. */ static int menuscan(Menu *menu, int but, Mouse *m, Rectangle textr, int off, int lasti, Image *save) { int i; paintitem(menu, textr, off, lasti, 1, save, nil); flushimage(display, 1); /* in case display->locking is set */ *m = emouse(); while(m->buttons & (1<<(but-1))){ flushimage(display, 1); /* in case display->locking is set */ *m = emouse(); i = menusel(textr, m->xy); if(i != -1 && i == lasti) continue; paintitem(menu, textr, off, lasti, 0, nil, save); if(i == -1) return i; lasti = i; paintitem(menu, textr, off, lasti, 1, save, nil); } return lasti; }
int movepiece(void) { Image *mask = nil; if(collide(Pt(pos.x, pos.y+pcsz), piece)) return 0; if(collider(pos, br2.max)) mask = bb2mask; draw(screen, rectaddpt(br2, pos), bb2, mask, bb2->r.min); pos.y += DY; flushimage(display, 1); return 1; }
void timeproc(void) { for(;;){ lockdisplay(display); drawtime(); updatetimes(); flushimage(display, 1); unlockdisplay(display); now = time(nil); sleep(((60 - now%60) + 1)*1000); /* wait for minute to change */ setdate(); } }
void dodelete(int i) { Face *f; f = faces[i]; if(history){ free(f->str[Sshow]); f->str[Sshow] = estrdup(""); }else{ delface(i); flushimage(display, 1); } }
void choosepiece(void) { int i; do { i = nrand(NP); setpiece(&pieces[i]); pos = rboard.min; pos.x += nrand(NX)*pcsz; } while(collide(Pt(pos.x, pos.y+pcsz-DY), piece)); drawpiece(); flushimage(display, 1); }
int loadimage(Image *i, Rectangle r, uchar *data, int ndata) { long dy; int n, bpl; uchar *a; int chunk; chunk = i->display->bufsize - 64; if(!rectinrect(r, i->r)){ werrstr("loadimage: bad rectangle"); return -1; } bpl = bytesperline(r, i->depth); n = bpl*Dy(r); if(n > ndata){ werrstr("loadimage: insufficient data"); return -1; } ndata = 0; while(r.max.y > r.min.y){ dy = r.max.y - r.min.y; if(dy*bpl > chunk) dy = chunk/bpl; if(dy <= 0){ werrstr("loadimage: image too wide for buffer"); return -1; } n = dy*bpl; a = bufimage(i->display, 21+n); if(a == nil){ werrstr("bufimage failed"); return -1; } a[0] = 'y'; BPLONG(a+1, i->id); BPLONG(a+5, r.min.x); BPLONG(a+9, r.min.y); BPLONG(a+13, r.max.x); BPLONG(a+17, r.min.y+dy); memmove(a+21, data, n); ndata += n; data += n; r.min.y += dy; } if(flushimage(i->display, 0) < 0) return -1; return ndata; }
void xfidctl(void *arg) { Xfid *x; void (*f)(Xfid*); threadsetname("xfidctlthread"); x = arg; for(;;){ f = (void(*)(Xfid*))recvp(x->c); (*f)(x); flushimage(display, 1); sendp(cxfidfree, x); } }
int _freeimage1(Image *i) { uchar *a; Display *d; Image *w; if(i == 0) return 0; /* make sure no refresh events occur on this if we block in the write */ d = i->display; /* flush pending data so we don't get error deleting the image */ flushimage(d, 0); a = bufimage(d, 1+4); if(a == 0) return -1; a[0] = 'f'; BPLONG(a+1, i->id); if(i->screen){ w = d->windows; if(w == i) d->windows = i->next; else while(w){ if(w->next == i){ w->next = i->next; break; } w = w->next; } } if(flushimage(d, i->screen!=0) < 0) return -1; return 0; }
void updatehistogram(double v) { char buf[32]; draw(screen, hrect, screen, nil, Pt(hrect.min.x+1, hrect.min.y)); if(v * scale > vmax) v = vmax / scale; drawdatum(hrect.max.x-1, data[0], v); memmove(&data[1], &data[0], (nval-1) * sizeof data[0]); data[0] = v; snprint(buf, sizeof buf, "%0.9f", v); stringbg(screen, maxvloc, txtcolor, ZP, display->defaultfont, buf, neutral, ZP); flushimage(display, 1); }
void pause(int t) { int s; Alt alts[NALT+1]; alts[TIMER].c = timerc; alts[TIMER].v = nil; alts[TIMER].op = CHANRCV; alts[SUSPEND].c = suspc; alts[SUSPEND].v = &s; alts[SUSPEND].op = CHANRCV; alts[RESHAPE].c = mousectl->resizec; alts[RESHAPE].v = nil; alts[RESHAPE].op = CHANRCV; // avoid hanging up those writing ong mousec and kbdc // so just accept it all and keep mouse up-to-date alts[MOUSE].c = mousec; alts[MOUSE].v = &mouse; alts[MOUSE].op = CHANRCV; alts[KBD].c = kbdc; alts[KBD].v = nil; alts[KBD].op = CHANRCV; alts[NALT].op = CHANEND; flushimage(display, 1); for(;;) switch(alt(alts)) { case SUSPEND: if (!suspended && s) { suspend(1); } else if (suspended && !s) { suspend(0); lastmx = warp(mouse.xy, lastmx); } break; case TIMER: if(suspended) break; if((t -= tsleep) < 0) return; break; case RESHAPE: redraw(1); break; } }
void addface(Face *f) /* always adds at 0 */ { Face **ofaces; Rectangle r0, r1, r; int y, nx, ny; if(f == nil) return; if(first != 0){ first = 0; eresized(0); } findbit(f); nx = nacross; ny = (nfaces+(nx-1)) / nx; lockdisplay(display); for(y=ny; y>=0; y--){ /* move them along */ r0 = facerect(y*nx+0); r1 = facerect(y*nx+1); r = r1; r.max.x = r.min.x + (nx - 1)*(Facesize+Facesep); draw(screen, r, screen, nil, r0.min); /* copy one down from row above */ if(y != 0){ r = facerect((y-1)*nx+nx-1); draw(screen, r0, screen, nil, r.min); } } ofaces = faces; faces = emalloc((nfaces+1)*sizeof(Face*)); memmove(faces+1, ofaces, nfaces*(sizeof(Face*))); free(ofaces); nfaces++; setlast(); drawarrows(); faces[0] = f; drawface(f, 0); flushimage(display, 1); unlockdisplay(display); }
void drawlevel(void) { Point p; int x, y, rx, ry, d; char *s = nil; if(finished) draw(screen, screen->r, finished==Won?won:lost, nil, ZP); else draw(screen, screen->r, bg, nil, ZP); d = (Dx(screen->r) > Dy(screen->r)) ? Dy(screen->r) -20: Dx(screen->r) -20; rx = (int)ceil((float)(d-2*Border)/(float)SzX)/2; ry = (int)ceil((float)(d-2*Border)/(float)SzY)/2; for(x = 0; x < SzX; x++) { for(y = 0; y < SzY; y++) { p = board2pix(x, y); switch(grid[x][y]){ case 999: fillellipse(screen, addpt(screen->r.min, p), rx, ry, cc, ZP); break; case 1000: p = addpt(screen->r.min, p); fillellipse(screen, p, rx, ry, ec, ZP); p = subpt(p, Pt(24, 24)); draw(screen, Rpt(p, addpt(p, Pt(48, 48))), gl, glm, ZP); break; default: fillellipse(screen, addpt(screen->r.min, p), rx, ry, ec, ZP); USED(s); /* uncomment the following to see game state and field scores */ /*s = smprint("%d", grid[x][y]); string(screen, addpt(screen->r.min, p), display->black, ZP, font, s); free(s); */ break; } } } flushimage(display, 1); }
int nameimage(Image *i, char *name, int in) { uchar *a; int n; n = strlen(name); a = bufimage(i->display, 1+4+1+1+n); if(a == 0) return 0; a[0] = 'N'; BPLONG(a+1, i->id); a[5] = in; a[6] = n; memmove(a+7, name, n); if(flushimage(i->display, 0) < 0) return 0; return 1; }