1 #include "lib9.h" 2 #include "draw.h" 3 #include "kernel.h" 4 #include "interp.h" 5 6 int _drawdebug; 7 8 enum { 9 CHECKLOCKING = 0 10 }; 11 12 /* 13 * Attach, or possibly reattach, to window. 14 * If reattaching, maintain value of screen pointer. 15 */ 16 int 17 gengetwindow(Display *d, char *winname, Image **winp, Screen **scrp, int ref) 18 { 19 int n, fd; 20 char buf[64+1]; 21 Image *image; 22 23 fd = libopen(winname, OREAD); 24 if(fd<0 || (n=libread(fd, buf, sizeof buf-1))<=0){ 25 *winp = d->image; 26 assert(*winp && (*winp)->chan != 0); 27 return 1; 28 } 29 libclose(fd); 30 buf[n] = '\0'; 31 if(*winp != nil){ 32 _freeimage1(*winp); 33 freeimage((*scrp)->image); 34 freescreen(*scrp); 35 *scrp = nil; 36 } 37 image = namedimage(d, buf); 38 if(image == 0){ 39 *winp = nil; 40 return -1; 41 } 42 assert(image->chan != 0); 43 44 *scrp = allocscreen(image, d->white, 0); 45 if(*scrp == nil){ 46 *winp = nil; 47 return -1; 48 } 49 50 *winp = _allocwindow(*winp, *scrp, insetrect(image->r, Borderwidth), ref, DWhite); 51 if(*winp == nil) 52 return -1; 53 assert((*winp)->chan != 0); 54 return 1; 55 } 56 57 #define NINFO 12*12 58 59 Display* 60 initdisplay(char *dev, char *win, void(*error)(Display*, char*)) 61 { 62 char buf[128], info[NINFO+1], *t; 63 int datafd, ctlfd, reffd; 64 Display *disp; 65 Image *image; 66 Dir *dir; 67 void *q; 68 ulong chan; 69 70 fmtinstall('P', Pfmt); 71 fmtinstall('R', Rfmt); 72 if(dev == 0) 73 dev = "/dev"; 74 if(win == 0) 75 win = "/dev"; 76 if(strlen(dev)>sizeof buf-25 || strlen(win)>sizeof buf-25){ 77 kwerrstr("initdisplay: directory name too long"); 78 return nil; 79 } 80 t = strdup(win); 81 if(t == nil) 82 return nil; 83 84 q = libqlalloc(); 85 if(q == nil) 86 return nil; 87 88 sprint(buf, "%s/draw/new", dev); 89 ctlfd = libopen(buf, ORDWR); 90 if(ctlfd < 0){ 91 if(libbind("#i", dev, MBEFORE) < 0){ 92 Error1: 93 libqlfree(q); 94 free(t); 95 kwerrstr("initdisplay: %s: %r", buf); 96 return 0; 97 } 98 ctlfd = libopen(buf, ORDWR); 99 } 100 if(ctlfd < 0) 101 goto Error1; 102 if(libread(ctlfd, info, sizeof info) < NINFO){ 103 Error2: 104 libclose(ctlfd); 105 goto Error1; 106 } 107 108 if((chan=strtochan(info+2*12)) == 0){ 109 kwerrstr("bad channel in %s", buf); 110 goto Error2; 111 } 112 113 sprint(buf, "%s/draw/%d/data", dev, atoi(info+0*12)); 114 datafd = libopen(buf, ORDWR); 115 if(datafd < 0) 116 goto Error2; 117 sprint(buf, "%s/draw/%d/refresh", dev, atoi(info+0*12)); 118 reffd = libopen(buf, OREAD); 119 if(reffd < 0){ 120 Error3: 121 libclose(datafd); 122 goto Error2; 123 } 124 strcpy(buf, "allocation failed"); 125 disp = malloc(sizeof(Display)); 126 if(disp == 0){ 127 Error4: 128 libclose(reffd); 129 goto Error3; 130 } 131 image = malloc(sizeof(Image)); 132 if(image == 0){ 133 Error5: 134 free(disp); 135 goto Error4; 136 } 137 memset(image, 0, sizeof(Image)); 138 memset(disp, 0, sizeof(Display)); 139 image->display = disp; 140 image->id = 0; 141 image->chan = chan; 142 image->depth = chantodepth(chan); 143 image->repl = atoi(info+3*12); 144 image->r.min.x = atoi(info+4*12); 145 image->r.min.y = atoi(info+5*12); 146 image->r.max.x = atoi(info+6*12); 147 image->r.max.y = atoi(info+7*12); 148 image->clipr.min.x = atoi(info+8*12); 149 image->clipr.min.y = atoi(info+9*12); 150 image->clipr.max.x = atoi(info+10*12); 151 image->clipr.max.y = atoi(info+11*12); 152 disp->dirno = atoi(info+0*12); 153 disp->datachan = libfdtochan(datafd, ORDWR); 154 disp->refchan = libfdtochan(reffd, OREAD); 155 disp->ctlchan = libfdtochan(ctlfd, ORDWR); 156 if(disp->datachan == nil || disp->refchan == nil || disp->ctlchan == nil) 157 goto Error4; 158 disp->bufsize = Displaybufsize; /* TO DO: iounit(datafd) */ 159 if(disp->bufsize <= 0) 160 disp->bufsize = Displaybufsize; 161 if(disp->bufsize < 512){ 162 kwerrstr("iounit %d too small", disp->bufsize); 163 goto Error5; 164 } 165 /* TO DO: allocate buffer */ 166 167 libclose(datafd); 168 libclose(reffd); 169 disp->image = image; 170 disp->bufp = disp->buf; 171 disp->error = error; 172 disp->chan = image->chan; 173 disp->depth = image->depth; 174 disp->windir = t; 175 disp->devdir = strdup(dev); 176 disp->qlock = q; 177 libqlock(q); 178 disp->white = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DWhite); 179 disp->black = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DBlack); 180 disp->opaque = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DWhite); 181 disp->transparent = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DBlack); 182 if(disp->white == nil || disp->black == nil || disp->opaque == nil || disp->transparent == nil){ 183 free(image); 184 free(disp->devdir); 185 free(disp->white); 186 free(disp->black); 187 libclose(ctlfd); 188 goto Error5; 189 } 190 if((dir = libdirfstat(ctlfd))!=nil && dir->type=='i'){ 191 disp->local = 1; 192 disp->dataqid = dir->qid.path; 193 } 194 free(dir); 195 libclose(ctlfd); 196 197 if(CHECKLOCKING) 198 disp->local = 0; /* force display locking even for local access */ 199 200 assert(disp->chan != 0 && image->chan != 0); 201 return disp; 202 } 203 204 /* 205 * Call with d unlocked. 206 * Note that disp->defaultfont and defaultsubfont are not freed here. 207 */ 208 void 209 closedisplay(Display *disp) 210 { 211 int fd; 212 char buf[128]; 213 214 if(disp == nil) 215 return; 216 libqlock(disp->qlock); 217 if(disp->oldlabel[0]){ 218 snprint(buf, sizeof buf, "%s/label", disp->windir); 219 fd = libopen(buf, OWRITE); 220 if(fd >= 0){ 221 libwrite(fd, disp->oldlabel, strlen(disp->oldlabel)); 222 libclose(fd); 223 } 224 } 225 226 free(disp->devdir); 227 free(disp->windir); 228 freeimage(disp->white); 229 freeimage(disp->black); 230 freeimage(disp->opaque); 231 freeimage(disp->transparent); 232 free(disp->image); 233 libchanclose(disp->datachan); 234 libchanclose(disp->refchan); 235 libchanclose(disp->ctlchan); 236 /* should cause refresh slave to shut down */ 237 libqunlock(disp->qlock); 238 libqlfree(disp->qlock); 239 free(disp); 240 } 241 242 int 243 lockdisplay(Display *disp) 244 { 245 if(disp->local) 246 return 0; 247 if(libqlowner(disp->qlock) != currun()){ 248 libqlock(disp->qlock); 249 return 1; 250 } 251 return 0; 252 } 253 254 void 255 unlockdisplay(Display *disp) 256 { 257 if(disp->local) 258 return; 259 libqunlock(disp->qlock); 260 } 261 262 /* use static buffer to avoid stack bloat */ 263 int 264 _drawprint(int fd, char *fmt, ...) 265 { 266 int n; 267 va_list arg; 268 char buf[128]; 269 // static QLock l; 270 271 // qlock(&l); 272 va_start(arg, fmt); 273 vseprint(buf, buf+sizeof buf, fmt, arg); 274 va_end(arg); 275 n = libwrite(fd, buf, strlen(buf)); 276 // qunlock(&l); 277 return n; 278 } 279 280 #ifdef YYY 281 void 282 drawerror(Display *d, char *s) 283 { 284 char err[ERRMAX]; 285 286 if(d->error) 287 d->error(d, s); 288 else{ 289 err[0] = 0; 290 errstr(err, sizeof err); 291 _drawprint(2, "draw: %s: %s\n", s, err); 292 exits(s); 293 } 294 } 295 296 static 297 int 298 doflush(Display *d) 299 { 300 int n; 301 302 n = d->bufp-d->buf; 303 if(n <= 0) 304 return 1; 305 306 if(kchanio(d->datachan, d->buf, n, OWRITE) != n){ 307 if(_drawdebug) 308 _drawprint(2, "flushimage fail: d=%p: %r\n", d); /**/ 309 d->bufp = d->buf; /* might as well; chance of continuing */ 310 return -1; 311 } 312 d->bufp = d->buf; 313 return 1; 314 } 315 316 int 317 flushimage(Display *d, int visible) 318 { 319 if(visible) 320 *d->bufp++ = 'v'; /* one byte always reserved for this */ 321 return doflush(d); 322 } 323 324 uchar* 325 bufimage(Display *d, int n) 326 { 327 uchar *p; 328 329 if(n<0 || n>Displaybufsize){ 330 kwerrstr("bad count in bufimage"); 331 return 0; 332 } 333 if(d->bufp+n > d->buf+Displaybufsize) 334 if(doflush(d) < 0) 335 return 0; 336 p = d->bufp; 337 d->bufp += n; 338 return p; 339 } 340 341 #endif 342