#include <string.h>#include <stdio.h>#include <fcntl.h>#include <error.h>#include <errno.h>#include "draw.h" #define _drawdebug 1 Display *display;Font *font;Image *screen;Screen *_screen;Point ZP; static int screenid; staticintunitsperline(Rectangle r, int d, int bitsperunit){ ulong l, t; if(d <= 0 || d > 32) /* being called wrong. d is image depth. */ abort(); if(r.min.x >= 0){ l = (r.max.x*d+bitsperunit-1)/bitsperunit; l -= (r.min.x*d)/bitsperunit; }else{ /* make positive before divide */ t = (-r.min.x*d+bitsperunit-1)/bitsperunit; l = t+(r.max.x*d+bitsperunit-1)/bitsperunit; } return l;} intwordsperline(Rectangle r, int d){ return unitsperline(r, d, 8*sizeof(ulong));} intrgb2cmap(int cr, int cg, int cb){ int i, r, g, b, sq; ulong rgb; int best, bestsq; best = 0; bestsq = 0x7FFFFFFF; for(i=0; i<256; i++){ rgb = cmap2rgb(i); r = (rgb>>16) & 0xFF; g = (rgb>>8) & 0xFF; b = (rgb>>0) & 0xFF; sq = (r-cr)*(r-cr)+(g-cg)*(g-cg)+(b-cb)*(b-cb); if(sq < bestsq){ bestsq = sq; best = i; } } return best;} intcmap2rgb(int c){ int j, num, den, r, g, b, v, rgb; r = c>>6; v = (c>>4)&3; j = (c-v+r)&15; g = j>>2; b = j&3; den=r; if(g>den) den=g; if(b>den) den=b; if(den==0) { v *= 17; rgb = (v<<16)|(v<<8)|v; } else{ num=17*(4*den+v); rgb = ((r*num/den)<<16)|((g*num/den)<<8)|(b*num/den); } return rgb;} intcmap2rgba(int c){ return (cmap2rgb(c)<<8)|0xFF;} Screen*allocscreen(Image *image, Image *fill, int public){ uchar *a; Screen *s; int id, try; Display *d; d = image->display; if(d != fill->display){ fprintf(stderr, "allocscreen: image and fill on different displays"); return nil; } s = malloc(sizeof(Screen)); if(s == nil) return nil; if(!screenid) screenid = getpid(); for(try=0; try<25; try++){ /* loop until find a free id */ a = bufimage(d, 1+4+4+4+1); if(a == nil) break; id = ++screenid & 0xffff; /* old devdraw bug */ a[0] = 'A'; BPLONG(a+1, id); BPLONG(a+5, image->id); BPLONG(a+9, fill->id); a[13] = public; if(flushimage(d, 0) != -1) goto Found; } free(s); return nil; Found: s->display = d; s->id = id; s->image = image; if(s->image != nil && s->image->chan != 0){ s->fill = fill; return s; } exit(-1);} intfreescreen(Screen *s){ uchar *a; Display *d; if(s == nil) return 0; d = s->display; a = bufimage(d, 1+4); if(a == nil){Error: free(s); return -1; } a[0] = 'F'; BPLONG(a+1, s->id); /* * flush(1) because screen is likely holding last reference to * window, and want it to disappear visually. */ if(flushimage(d, 1) < 0) goto Error; free(s); return 1;} Image*_allocwindow(Image *i, Screen *s, Rectangle r, int ref, ulong col){ Display *d; d = s->display; i = _allocimage(i, d, r, d->screenimage->chan, 0, col, s->id, ref); if(i == nil) return nil; i->screen = s; i->next = s->display->windows; s->display->windows = i; return i;} Image*namedimage(Display *d, char *name){ uchar *a; char *err, buf[12*12+1]; Image *i; int id, n; ulong chan; err = nil; i = nil; n = strlen(name); if(n >= 256){ err = "name too long"; Error: if(err != nil) fprintf(stderr,"namedimage: %s", err); else fprintf(stderr,"namedimage: %s", strerror(errno)); free(i); return nil; } /* flush pending data so we don't get error allocating the image */ flushimage(d, 0); a = bufimage(d, 1+4+1+n); if(a == nil) goto Error; d->imageid++; id = d->imageid; a[0] = 'n'; BPLONG(a+1, id); a[5] = n; memmove(a+6, name, n); if(flushimage(d, 0) < 0) goto Error; if(pread(d->ctlfd, buf, 12*12, 0) < 12*12) goto Error; buf[12*12] = '\0'; i = malloc(sizeof(Image)); if(i == nil){ Error1: a = bufimage(d, 1+4); if(a != nil){ a[0] = 'f'; BPLONG(a+1, id); flushimage(d, 0); } goto Error; } i->display = d; i->id = id; if((chan=strtochan(buf+2*12))==0){ fprintf(stderr, "bad channel '%.12s' from devdraw", buf+2*12); goto Error1; } i->chan = chan; i->depth = chantodepth(chan); i->repl = atoi(buf+3*12); i->r.min.x = atoi(buf+4*12); i->r.min.y = atoi(buf+5*12); i->r.max.x = atoi(buf+6*12); i->r.max.y = atoi(buf+7*12); i->clipr.min.x = atoi(buf+8*12); i->clipr.min.y = atoi(buf+9*12); i->clipr.max.x = atoi(buf+10*12); i->clipr.max.y = atoi(buf+11*12); i->screen = nil; i->next = nil; return i;} void_setdrawop(Display *d, Drawop op){ uchar *a; if(op != SoverD){ a = bufimage(d, 1+1); if(a == nil) return; a[0] = 'O'; a[1] = op; }} static voiddraw1(Image *dst, Rectangle *r, Image *src, Point *p0, Image *mask, Point *p1, Drawop op){ uchar *a; _setdrawop(dst->display, op); a = bufimage(dst->display, 1+4+4+4+4*4+2*4+2*4); if(a == nil) return; if(src == nil) src = dst->display->black; if(mask == nil) mask = dst->display->opaque; a[0] = 'd'; BPLONG(a+1, dst->id); BPLONG(a+5, src->id); BPLONG(a+9, mask->id); BPLONG(a+13, r->min.x); BPLONG(a+17, r->min.y); BPLONG(a+21, r->max.x); BPLONG(a+25, r->max.y); BPLONG(a+29, p0->x); BPLONG(a+33, p0->y); BPLONG(a+37, p1->x); BPLONG(a+41, p1->y); } voiddraw(Image *dst, Rectangle r, Image *src, Image *mask, Point p1){ draw1(dst, &r, src, &p1, mask, &p1, SoverD);} int_freeimage1(Image *i){ uchar *a; Display *d; Image *w; if(i == nil || i->display == nil) return 0; d = i->display; if(i->screen != nil){ w = d->windows; if(w == i) d->windows = i->next; else while(w != nil){ if(w->next == i){ w->next = i->next; break; } w = w->next; } } a = bufimage(d, 1+4); if(a == nil) return -1; a[0] = 'f'; BPLONG(a+1, i->id); return 0;} intfreeimage(Image *i){ int ret; ret = _freeimage1(i); free(i); return ret;} static void_closedisplay(Display *disp, int isshutdown){ int fd; char buf[128]; if(disp == nil) return; if(disp == display) display = nil; if(disp->oldlabel[0]){ snprintf(buf, sizeof buf, "%s/label", disp->windir); fd = open(buf, O_WRONLY); if(fd >= 0){ write(fd, disp->oldlabel, strlen(disp->oldlabel)); close(fd); } } /* * if we're shutting down, don't free all the resources. * if other procs are getting shot down by notes too, * one might get shot down while holding the malloc lock. * just let the kernel clean things up when we exit. */ if(isshutdown) return; free(disp->devdir); free(disp->windir); freeimage(disp->white); freeimage(disp->black); close(disp->fd); close(disp->ctlfd); /* should cause refresh slave to shut down */ close(disp->reffd); /* qunlock(&disp->qlock); TODO */ free(disp);} voidclosedisplay(Display *disp){ _closedisplay(disp, 0);} /* note handler */static voiddrawshutdown(void){ Display *d; d = display; if(d != nil){ display = nil; _closedisplay(d, 1); }} PointPt(int x, int y){ Point p; p.x = x; p.y = y; return p;} RectangleRect(int x, int y, int bx, int by){ Rectangle r; r.min.x = x; r.min.y = y; r.max.x = bx; r.max.y = by; return r;} Rectangleinsetrect(Rectangle r, int n){ r.min.x += n; r.min.y += n; r.max.x -= n; r.max.y -= n; return r;} intbadrect(Rectangle r){ int x, y; uint z; x = Dx(r); y = Dy(r); if(x > 0 && y > 0){ z = x*y; if(z/x == y && z < 0x10000000) return 0; } return 1;} static char channames[] = "rgbkamx"; intchantodepth(ulong c){ int n; for(n=0; c; c>>=8){ if(TYPE(c) >= NChan || NBITS(c) > 8 || NBITS(c) <= 0) return 0; n += NBITS(c); } if(n==0 || (n>8 && n%8) || (n<8 && 8%n)) return 0; return n;} ulongstrtochan(char *s){ char *p, *q; ulong c; int t, n, d; c = 0; d = 0; p=s; while(*p && isspace(*p)) p++; while(*p && !isspace(*p)){ if((q = strchr(channames, p[0])) == nil) return 0; t = q-channames; if(p[1] < '0' || p[1] > '9') return 0; n = p[1]-'0'; d += n; c = (c<<8) | __DC(t, n); p += 2; } if(d==0 || (d>8 && d%8) || (d<8 && 8%d)) return 0; return c;Lines 1–500 of 884. Load more
#include <string.h> #include <stdio.h> #include <fcntl.h> #include <error.h> #include <errno.h> #include "draw.h" #define _drawdebug 1 Display *display; Font *font; Image *screen; Screen *_screen; Point ZP; static int screenid; static int unitsperline(Rectangle r, int d, int bitsperunit) { ulong l, t; if(d <= 0 || d > 32) /* being called wrong. d is image depth. */ abort(); if(r.min.x >= 0){ l = (r.max.x*d+bitsperunit-1)/bitsperunit; l -= (r.min.x*d)/bitsperunit; }else{ /* make positive before divide */ t = (-r.min.x*d+bitsperunit-1)/bitsperunit; l = t+(r.max.x*d+bitsperunit-1)/bitsperunit; } return l; } int wordsperline(Rectangle r, int d) { return unitsperline(r, d, 8*sizeof(ulong)); } int rgb2cmap(int cr, int cg, int cb) { int i, r, g, b, sq; ulong rgb; int best, bestsq; best = 0; bestsq = 0x7FFFFFFF; for(i=0; i<256; i++){ rgb = cmap2rgb(i); r = (rgb>>16) & 0xFF; g = (rgb>>8) & 0xFF; b = (rgb>>0) & 0xFF; sq = (r-cr)*(r-cr)+(g-cg)*(g-cg)+(b-cb)*(b-cb); if(sq < bestsq){ bestsq = sq; best = i; } } return best; } int cmap2rgb(int c) { int j, num, den, r, g, b, v, rgb; r = c>>6; v = (c>>4)&3; j = (c-v+r)&15; g = j>>2; b = j&3; den=r; if(g>den) den=g; if(b>den) den=b; if(den==0) { v *= 17; rgb = (v<<16)|(v<<8)|v; } else{ num=17*(4*den+v); rgb = ((r*num/den)<<16)|((g*num/den)<<8)|(b*num/den); } return rgb; } int cmap2rgba(int c) { return (cmap2rgb(c)<<8)|0xFF; } Screen* allocscreen(Image *image, Image *fill, int public) { uchar *a; Screen *s; int id, try; Display *d; d = image->display; if(d != fill->display){ fprintf(stderr, "allocscreen: image and fill on different displays"); return nil; } s = malloc(sizeof(Screen)); if(s == nil) return nil; if(!screenid) screenid = getpid(); for(try=0; try<25; try++){ /* loop until find a free id */ a = bufimage(d, 1+4+4+4+1); if(a == nil) break; id = ++screenid & 0xffff; /* old devdraw bug */ a[0] = 'A'; BPLONG(a+1, id); BPLONG(a+5, image->id); BPLONG(a+9, fill->id); a[13] = public; if(flushimage(d, 0) != -1) goto Found; } free(s); return nil; Found: s->display = d; s->id = id; s->image = image; if(s->image != nil && s->image->chan != 0){ s->fill = fill; return s; } exit(-1); } int freescreen(Screen *s) { uchar *a; Display *d; if(s == nil) return 0; d = s->display; a = bufimage(d, 1+4); if(a == nil){ Error: free(s); return -1; } a[0] = 'F'; BPLONG(a+1, s->id); /* * flush(1) because screen is likely holding last reference to * window, and want it to disappear visually. */ if(flushimage(d, 1) < 0) goto Error; free(s); return 1; } Image* _allocwindow(Image *i, Screen *s, Rectangle r, int ref, ulong col) { Display *d; d = s->display; i = _allocimage(i, d, r, d->screenimage->chan, 0, col, s->id, ref); if(i == nil) return nil; i->screen = s; i->next = s->display->windows; s->display->windows = i; return i; } Image* namedimage(Display *d, char *name) { uchar *a; char *err, buf[12*12+1]; Image *i; int id, n; ulong chan; err = nil; i = nil; n = strlen(name); if(n >= 256){ err = "name too long"; Error: if(err != nil) fprintf(stderr,"namedimage: %s", err); else fprintf(stderr,"namedimage: %s", strerror(errno)); free(i); return nil; } /* flush pending data so we don't get error allocating the image */ flushimage(d, 0); a = bufimage(d, 1+4+1+n); if(a == nil) goto Error; d->imageid++; id = d->imageid; a[0] = 'n'; BPLONG(a+1, id); a[5] = n; memmove(a+6, name, n); if(flushimage(d, 0) < 0) goto Error; if(pread(d->ctlfd, buf, 12*12, 0) < 12*12) goto Error; buf[12*12] = '\0'; i = malloc(sizeof(Image)); if(i == nil){ Error1: a = bufimage(d, 1+4); if(a != nil){ a[0] = 'f'; BPLONG(a+1, id); flushimage(d, 0); } goto Error; } i->display = d; i->id = id; if((chan=strtochan(buf+2*12))==0){ fprintf(stderr, "bad channel '%.12s' from devdraw", buf+2*12); goto Error1; } i->chan = chan; i->depth = chantodepth(chan); i->repl = atoi(buf+3*12); i->r.min.x = atoi(buf+4*12); i->r.min.y = atoi(buf+5*12); i->r.max.x = atoi(buf+6*12); i->r.max.y = atoi(buf+7*12); i->clipr.min.x = atoi(buf+8*12); i->clipr.min.y = atoi(buf+9*12); i->clipr.max.x = atoi(buf+10*12); i->clipr.max.y = atoi(buf+11*12); i->screen = nil; i->next = nil; return i; } void _setdrawop(Display *d, Drawop op) { uchar *a; if(op != SoverD){ a = bufimage(d, 1+1); if(a == nil) return; a[0] = 'O'; a[1] = op; } } static void draw1(Image *dst, Rectangle *r, Image *src, Point *p0, Image *mask, Point *p1, Drawop op) { uchar *a; _setdrawop(dst->display, op); a = bufimage(dst->display, 1+4+4+4+4*4+2*4+2*4); if(a == nil) return; if(src == nil) src = dst->display->black; if(mask == nil) mask = dst->display->opaque; a[0] = 'd'; BPLONG(a+1, dst->id); BPLONG(a+5, src->id); BPLONG(a+9, mask->id); BPLONG(a+13, r->min.x); BPLONG(a+17, r->min.y); BPLONG(a+21, r->max.x); BPLONG(a+25, r->max.y); BPLONG(a+29, p0->x); BPLONG(a+33, p0->y); BPLONG(a+37, p1->x); BPLONG(a+41, p1->y); } void draw(Image *dst, Rectangle r, Image *src, Image *mask, Point p1) { draw1(dst, &r, src, &p1, mask, &p1, SoverD); } int _freeimage1(Image *i) { uchar *a; Display *d; Image *w; if(i == nil || i->display == nil) return 0; d = i->display; if(i->screen != nil){ w = d->windows; if(w == i) d->windows = i->next; else while(w != nil){ if(w->next == i){ w->next = i->next; break; } w = w->next; } } a = bufimage(d, 1+4); if(a == nil) return -1; a[0] = 'f'; BPLONG(a+1, i->id); return 0; } int freeimage(Image *i) { int ret; ret = _freeimage1(i); free(i); return ret; } static void _closedisplay(Display *disp, int isshutdown) { int fd; char buf[128]; if(disp == nil) return; if(disp == display) display = nil; if(disp->oldlabel[0]){ snprintf(buf, sizeof buf, "%s/label", disp->windir); fd = open(buf, O_WRONLY); if(fd >= 0){ write(fd, disp->oldlabel, strlen(disp->oldlabel)); close(fd); } } /* * if we're shutting down, don't free all the resources. * if other procs are getting shot down by notes too, * one might get shot down while holding the malloc lock. * just let the kernel clean things up when we exit. */ if(isshutdown) return; free(disp->devdir); free(disp->windir); freeimage(disp->white); freeimage(disp->black); close(disp->fd); close(disp->ctlfd); /* should cause refresh slave to shut down */ close(disp->reffd); /* qunlock(&disp->qlock); TODO */ free(disp); } void closedisplay(Display *disp) { _closedisplay(disp, 0); } /* note handler */ static void drawshutdown(void) { Display *d; d = display; if(d != nil){ display = nil; _closedisplay(d, 1); } } Point Pt(int x, int y) { Point p; p.x = x; p.y = y; return p; } Rectangle Rect(int x, int y, int bx, int by) { Rectangle r; r.min.x = x; r.min.y = y; r.max.x = bx; r.max.y = by; return r; } Rectangle insetrect(Rectangle r, int n) { r.min.x += n; r.min.y += n; r.max.x -= n; r.max.y -= n; return r; } int badrect(Rectangle r) { int x, y; uint z; x = Dx(r); y = Dy(r); if(x > 0 && y > 0){ z = x*y; if(z/x == y && z < 0x10000000) return 0; } return 1; } static char channames[] = "rgbkamx"; int chantodepth(ulong c) { int n; for(n=0; c; c>>=8){ if(TYPE(c) >= NChan || NBITS(c) > 8 || NBITS(c) <= 0) return 0; n += NBITS(c); } if(n==0 || (n>8 && n%8) || (n<8 && 8%n)) return 0; return n; } ulong strtochan(char *s) { char *p, *q; ulong c; int t, n, d; c = 0; d = 0; p=s; while(*p && isspace(*p)) p++; while(*p && !isspace(*p)){ if((q = strchr(channames, p[0])) == nil) return 0; t = q-channames; if(p[1] < '0' || p[1] > '9') return 0; n = p[1]-'0'; d += n; c = (c<<8) | __DC(t, n); p += 2; } if(d==0 || (d>8 && d%8) || (d<8 && 8%d)) return 0; return c;