tinit.c - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
LICENSE
---
tinit.c (9140B)
---
     1 #include 
     2 #include 
     3 #include 
     4 #include 
     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 }