URI:
       tinit.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tinit.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 }