init.c (9140B)
1 #include <u.h> 2 #include <libc.h> 3 #include <draw.h> 4 #include <mouse.h> 5 6 Display *display; 7 Font *font; 8 Image *screen; 9 int _drawdebug; 10 11 Screen *_screen; 12 13 int debuglockdisplay = 1; 14 char *winsize; 15 16 int visibleclicks = 0; 17 Image *mousebuttons; 18 Image *mousesave; 19 Mouse _drawmouse; 20 21 void 22 needdisplay(void) 23 { 24 } 25 26 /* 27 static void 28 drawshutdown(void) 29 { 30 Display *d; 31 32 d = display; 33 if(d){ 34 display = nil; 35 closedisplay(d); 36 } 37 } 38 */ 39 40 int 41 geninitdraw(char *devdir, void(*error)(Display*, char*), char *fontname, char *label, char *windir, int ref) 42 { 43 char *p; 44 45 if(label == nil) 46 label = argv0; 47 display = _initdisplay(error, label); 48 if(display == nil) 49 return -1; 50 51 /* 52 * Set up default font 53 */ 54 if(openfont(display, "*default*") == 0) { 55 fprint(2, "imageinit: can't open default subfont: %r\n"); 56 Error: 57 closedisplay(display); 58 display = nil; 59 return -1; 60 } 61 if(fontname == nil) 62 fontname = getenv("font"); 63 64 /* 65 * Build fonts with caches==depth of screen, for speed. 66 * If conversion were faster, we'd use 0 and save memory. 67 */ 68 if(fontname == nil) 69 fontname = strdup("*default*"); 70 71 font = openfont(display, fontname); 72 if(font == nil){ 73 fprint(2, "imageinit: can't open font %s: %r\n", fontname); 74 goto Error; 75 } 76 display->defaultfont = font; 77 78 _screen = allocscreen(display->image, display->white, 0); 79 display->screenimage = display->image; /* _allocwindow wants screenimage->chan */ 80 screen = _allocwindow(nil, _screen, display->image->r, Refnone, DWhite); 81 if(screen == nil){ 82 fprint(2, "_allocwindow: %r\n"); 83 goto Error; 84 } 85 display->screenimage = screen; 86 draw(screen, screen->r, display->white, nil, ZP); 87 flushimage(display, 1); 88 89 p = getenv("visibleclicks"); 90 visibleclicks = p != nil && *p == '1'; 91 if(visibleclicks) { 92 Font *f; 93 94 f = display->defaultfont; 95 mousebuttons = allocimage(display, Rect(0,0,64,22), screen->chan, 0, DWhite); 96 border(mousebuttons, mousebuttons->r, 1, display->black, ZP); 97 border(mousebuttons, Rect(0, 0, 22, 22), 1, display->black, ZP); 98 border(mousebuttons, Rect(42, 0, 64, 22), 1, display->black, ZP); 99 string(mousebuttons, Pt(10-stringwidth(display->defaultfont, "1")/2, 11-f->height/2), display->black, ZP, display->defaultfont, "1"); 100 string(mousebuttons, Pt(21+10-stringwidth(display->defaultfont, "2")/2, 11-f->height/2), display->black, ZP, display->defaultfont, "2"); 101 string(mousebuttons, Pt(42+10-stringwidth(display->defaultfont, "3")/2, 11-f->height/2), display->black, ZP, display->defaultfont, "3"); 102 mousesave = allocimage(display, Rect(0,0,64,22), screen->chan, 0, 0); 103 } 104 105 /* 106 * I don't see any reason to go away gracefully, 107 * and if some other proc exits holding the display 108 * lock, this atexit call never finishes. 109 * 110 * atexit(drawshutdown); 111 */ 112 return 1; 113 } 114 115 int 116 initdraw(void (*error)(Display*, char*), char *fontname, char *label) 117 { 118 return geninitdraw("/dev", error, fontname, label, "/dev", Refnone); 119 } 120 121 extern int _freeimage1(Image*); 122 123 static Image* 124 getimage0(Display *d, Image *image) 125 { 126 char info[12*12+1]; 127 uchar *a; 128 int n; 129 130 /* 131 * If there's an old screen, it has id 0. The 'J' request below 132 * will try to install the new screen as id 0, so the old one 133 * must be freed first. 134 */ 135 if(image){ 136 _freeimage1(image); 137 memset(image, 0, sizeof(Image)); 138 } 139 140 a = bufimage(d, 2); 141 a[0] = 'J'; 142 a[1] = 'I'; 143 if(flushimage(d, 0) < 0){ 144 fprint(2, "cannot read screen info: %r\n"); 145 return nil; 146 } 147 148 n = _displayrddraw(d, info, sizeof info); 149 if(n != 12*12){ 150 fprint(2, "short screen info\n"); 151 return nil; 152 } 153 154 if(image == nil){ 155 image = mallocz(sizeof(Image), 1); 156 if(image == nil){ 157 fprint(2, "cannot allocate image: %r\n"); 158 return nil; 159 } 160 } 161 162 image->display = d; 163 image->id = 0; 164 image->chan = strtochan(info+2*12); 165 image->depth = chantodepth(image->chan); 166 image->repl = atoi(info+3*12); 167 image->r.min.x = atoi(info+4*12); 168 image->r.min.y = atoi(info+5*12); 169 image->r.max.x = atoi(info+6*12); 170 image->r.max.y = atoi(info+7*12); 171 image->clipr.min.x = atoi(info+8*12); 172 image->clipr.min.y = atoi(info+9*12); 173 image->clipr.max.x = atoi(info+10*12); 174 image->clipr.max.y = atoi(info+11*12); 175 176 a = bufimage(d, 3); 177 a[0] = 'q'; 178 a[1] = 1; 179 a[2] = 'd'; 180 d->dpi = 100; 181 if(flushimage(d, 0) >= 0 && _displayrddraw(d, info, 12) == 12) 182 d->dpi = atoi(info); 183 184 return image; 185 } 186 187 /* 188 * Attach, or possibly reattach, to window. 189 * If reattaching, maintain value of screen pointer. 190 */ 191 int 192 getwindow(Display *d, int ref) 193 { 194 Image *i, *oi; 195 Font *f; 196 197 /* XXX check for destroyed? */ 198 199 /* 200 * Libdraw promises not to change the value of "screen", 201 * so we have to reuse the image structure 202 * memory we already have. 203 */ 204 oi = d->image; 205 i = getimage0(d, oi); 206 if(i == nil) 207 sysfatal("getwindow failed"); 208 d->image = i; 209 /* fprint(2, "getwindow %p -> %p\n", oi, i); */ 210 211 freescreen(_screen); 212 _screen = allocscreen(i, d->white, 0); 213 _freeimage1(screen); 214 screen = _allocwindow(screen, _screen, i->r, ref, DWhite); 215 d->screenimage = screen; 216 217 218 if(d->dpi >= DefaultDPI*3/2) { 219 for(f=d->firstfont; f != nil; f=f->next) 220 loadhidpi(f); 221 } else { 222 for(f=d->firstfont; f != nil; f=f->next) 223 if(f->lodpi != nil && f->lodpi != f) 224 swapfont(f, &f->hidpi, &f->lodpi); 225 } 226 227 return 0; 228 } 229 230 Display* 231 _initdisplay(void (*error)(Display*, char*), char *label) 232 { 233 Display *disp; 234 Image *image; 235 236 fmtinstall('P', Pfmt); 237 fmtinstall('R', Rfmt); 238 239 disp = mallocz(sizeof(Display), 1); 240 if(disp == nil){ 241 Error1: 242 return nil; 243 } 244 disp->srvfd = -1; 245 image = nil; 246 if(0){ 247 Error2: 248 free(image); 249 free(disp); 250 goto Error1; 251 } 252 disp->bufsize = 65500; 253 disp->buf = malloc(disp->bufsize+5); /* +5 for flush message */ 254 disp->bufp = disp->buf; 255 disp->error = error; 256 qlock(&disp->qlock); 257 258 if(disp->buf == nil) 259 goto Error2; 260 if(0){ 261 Error3: 262 free(disp->buf); 263 goto Error2; 264 } 265 266 if(_displaymux(disp) < 0 267 || _displayconnect(disp) < 0 268 || _displayinit(disp, label, winsize) < 0) 269 goto Error3; 270 if(0){ 271 Error4: 272 close(disp->srvfd); 273 goto Error3; 274 } 275 276 image = getimage0(disp, nil); 277 if(image == nil) 278 goto Error4; 279 280 disp->image = image; 281 disp->white = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DWhite); 282 disp->black = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DBlack); 283 if(disp->white == nil || disp->black == nil){ 284 free(disp->white); 285 free(disp->black); 286 goto Error4; 287 } 288 289 disp->opaque = disp->white; 290 disp->transparent = disp->black; 291 292 return disp; 293 } 294 295 /* 296 * Call with d unlocked. 297 * Note that disp->defaultfont is not freed here. 298 */ 299 void 300 closedisplay(Display *disp) 301 { 302 int fd; 303 char buf[128]; 304 305 if(disp == nil) 306 return; 307 if(disp == display) 308 display = nil; 309 if(disp->oldlabel[0]){ 310 snprint(buf, sizeof buf, "%s/label", disp->windir); 311 fd = open(buf, OWRITE); 312 if(fd >= 0){ 313 write(fd, disp->oldlabel, strlen(disp->oldlabel)); 314 close(fd); 315 } 316 } 317 318 free(disp->devdir); 319 free(disp->windir); 320 if(disp->white) 321 freeimage(disp->white); 322 if(disp->black) 323 freeimage(disp->black); 324 if(disp->srvfd >= 0) 325 close(disp->srvfd); 326 free(disp); 327 } 328 329 void 330 lockdisplay(Display *disp) 331 { 332 if(debuglockdisplay){ 333 /* avoid busy looping; it's rare we collide anyway */ 334 while(!canqlock(&disp->qlock)){ 335 fprint(1, "proc %d waiting for display lock...\n", getpid()); 336 sleep(1000); 337 } 338 }else 339 qlock(&disp->qlock); 340 } 341 342 void 343 unlockdisplay(Display *disp) 344 { 345 qunlock(&disp->qlock); 346 } 347 348 void 349 drawerror(Display *d, char *s) 350 { 351 char err[ERRMAX]; 352 353 if(d->error) 354 d->error(d, s); 355 else{ 356 errstr(err, sizeof err); 357 fprint(2, "draw: %s: %s\n", s, err); 358 exits(s); 359 } 360 } 361 362 static 363 int 364 doflush(Display *d) 365 { 366 int n; 367 368 n = d->bufp-d->buf; 369 if(n <= 0) 370 return 1; 371 372 if(_displaywrdraw(d, d->buf, n) != n){ 373 if(_drawdebug) 374 fprint(2, "flushimage fail: d=%p: %r\n", d); /**/ 375 d->bufp = d->buf; /* might as well; chance of continuing */ 376 return -1; 377 } 378 d->bufp = d->buf; 379 return 1; 380 } 381 382 int 383 flushimage(Display *d, int visible) 384 { 385 if(visible == 1 && visibleclicks && mousebuttons && _drawmouse.buttons) { 386 Rectangle r, r1; 387 int ret; 388 389 r = mousebuttons->r; 390 r = rectaddpt(r, _drawmouse.xy); 391 r = rectaddpt(r, Pt(-Dx(mousebuttons->r)/2, -Dy(mousebuttons->r)-3)); 392 drawop(mousesave, mousesave->r, screen, nil, r.min, S); 393 394 r1 = rectaddpt(Rect(0, 0, 22, 22), r.min); 395 if(_drawmouse.buttons & 1) 396 drawop(screen, r1, mousebuttons, nil, ZP, S); 397 r1 = rectaddpt(r1, Pt(21, 0)); 398 if(_drawmouse.buttons & 2) 399 drawop(screen, r1, mousebuttons, nil, Pt(21, 0), S); 400 r1 = rectaddpt(r1, Pt(21, 0)); 401 if(_drawmouse.buttons & 4) 402 drawop(screen, r1, mousebuttons, nil, Pt(42, 0), S); 403 ret = flushimage(d, 2); 404 drawop(screen, r, mousesave, nil, ZP, S); 405 return ret; 406 } 407 408 if(visible){ 409 *d->bufp++ = 'v'; /* five bytes always reserved for this */ 410 if(d->_isnewdisplay){ 411 BPLONG(d->bufp, d->screenimage->id); 412 d->bufp += 4; 413 } 414 } 415 return doflush(d); 416 } 417 418 uchar* 419 bufimage(Display *d, int n) 420 { 421 uchar *p; 422 423 if(n<0 || d == nil || n>d->bufsize){ 424 abort(); 425 werrstr("bad count in bufimage"); 426 return 0; 427 } 428 if(d->bufp+n > d->buf+d->bufsize) 429 if(doflush(d) < 0) 430 return 0; 431 p = d->bufp; 432 d->bufp += n; 433 return p; 434 } 435 436 int 437 scalesize(Display *d, int n) 438 { 439 if(d == nil || d->dpi <= DefaultDPI) 440 return n; 441 return (n*d->dpi+DefaultDPI/2)/DefaultDPI; 442 }