mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-15 11:20:03 +00:00
204 lines
3.7 KiB
C
204 lines
3.7 KiB
C
|
#include <u.h>
|
||
|
#include <libc.h>
|
||
|
#include <draw.h>
|
||
|
|
||
|
Display *display;
|
||
|
Font *font;
|
||
|
Image *screen;
|
||
|
int _drawdebug;
|
||
|
|
||
|
static char deffontname[] = "*default*";
|
||
|
Screen *_screen;
|
||
|
|
||
|
int debuglockdisplay = 0;
|
||
|
|
||
|
static void
|
||
|
drawshutdown(void)
|
||
|
{
|
||
|
Display *d;
|
||
|
|
||
|
d = display;
|
||
|
if(d){
|
||
|
display = nil;
|
||
|
closedisplay(d);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int
|
||
|
initdraw(void (*error)(Display*, char*), char *fontname, char *label)
|
||
|
{
|
||
|
Subfont *df;
|
||
|
char buf[128];
|
||
|
|
||
|
display = _initdisplay(error, label); /* sets screen too */
|
||
|
if(display == nil)
|
||
|
return -1;
|
||
|
|
||
|
display->image = display->screenimage;
|
||
|
screen = display->screenimage;
|
||
|
|
||
|
/*
|
||
|
* Set up default font
|
||
|
*/
|
||
|
df = getdefont(display);
|
||
|
display->defaultsubfont = df;
|
||
|
if(df == nil){
|
||
|
fprint(2, "imageinit: can't open default subfont: %r\n");
|
||
|
Error:
|
||
|
closedisplay(display);
|
||
|
display = nil;
|
||
|
return -1;
|
||
|
}
|
||
|
if(fontname == nil)
|
||
|
fontname = getenv("font"); /* leak */
|
||
|
|
||
|
/*
|
||
|
* Build fonts with caches==depth of screen, for speed.
|
||
|
* If conversion were faster, we'd use 0 and save memory.
|
||
|
*/
|
||
|
if(fontname == nil){
|
||
|
snprint(buf, sizeof buf, "%d %d\n0 %d\t%s\n", df->height, df->ascent,
|
||
|
df->n-1, deffontname);
|
||
|
//BUG: Need something better for this installsubfont("*default*", df);
|
||
|
font = buildfont(display, buf, deffontname);
|
||
|
if(font == nil){
|
||
|
fprint(2, "initdraw: can't open default font: %r\n");
|
||
|
goto Error;
|
||
|
}
|
||
|
}else{
|
||
|
font = openfont(display, fontname); /* BUG: grey fonts */
|
||
|
if(font == nil){
|
||
|
fprint(2, "initdraw: can't open font %s: %r\n", fontname);
|
||
|
goto Error;
|
||
|
}
|
||
|
}
|
||
|
display->defaultfont = font;
|
||
|
|
||
|
display->white = allocimage(display, Rect(0,0,1,1), GREY1, 1, DWhite);
|
||
|
display->black = allocimage(display, Rect(0,0,1,1), GREY1, 1, DBlack);
|
||
|
if(display->white == nil || display->black == nil){
|
||
|
fprint(2, "initdraw: can't allocate white and black");
|
||
|
goto Error;
|
||
|
}
|
||
|
display->opaque = display->white;
|
||
|
display->transparent = display->black;
|
||
|
atexit(drawshutdown);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Call with d unlocked.
|
||
|
* Note that disp->defaultfont and defaultsubfont are not freed here.
|
||
|
*/
|
||
|
void
|
||
|
closedisplay(Display *disp)
|
||
|
{
|
||
|
int fd;
|
||
|
char buf[128];
|
||
|
|
||
|
if(disp == nil)
|
||
|
return;
|
||
|
if(disp == display)
|
||
|
display = nil;
|
||
|
if(disp->oldlabel[0]){
|
||
|
snprint(buf, sizeof buf, "%s/label", disp->windir);
|
||
|
fd = open(buf, OWRITE);
|
||
|
if(fd >= 0){
|
||
|
write(fd, disp->oldlabel, strlen(disp->oldlabel));
|
||
|
close(fd);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
free(disp->devdir);
|
||
|
free(disp->windir);
|
||
|
freeimage(disp->white);
|
||
|
freeimage(disp->black);
|
||
|
qunlock(&disp->qlock);
|
||
|
free(disp);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
lockdisplay(Display *disp)
|
||
|
{
|
||
|
if(debuglockdisplay){
|
||
|
/* avoid busy looping; it's rare we collide anyway */
|
||
|
while(!canqlock(&disp->qlock)){
|
||
|
fprint(1, "proc %d waiting for display lock...\n", getpid());
|
||
|
sleep(1000);
|
||
|
}
|
||
|
}else
|
||
|
qlock(&disp->qlock);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
unlockdisplay(Display *disp)
|
||
|
{
|
||
|
qunlock(&disp->qlock);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
drawerror(Display *d, char *s)
|
||
|
{
|
||
|
char err[ERRMAX];
|
||
|
|
||
|
if(d->error)
|
||
|
d->error(d, s);
|
||
|
else{
|
||
|
errstr(err, sizeof err);
|
||
|
fprint(2, "draw: %s: %s\n", s, err);
|
||
|
exits(s);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static
|
||
|
int
|
||
|
doflush(Display *d)
|
||
|
{
|
||
|
int n;
|
||
|
|
||
|
n = d->bufp-d->buf;
|
||
|
if(n <= 0)
|
||
|
return 1;
|
||
|
|
||
|
if(_drawmsgwrite(d, d->buf, n) != n){
|
||
|
if(_drawdebug)
|
||
|
fprint(2, "flushimage fail: d=%p: %r\n", d); /**/
|
||
|
d->bufp = d->buf; /* might as well; chance of continuing */
|
||
|
return -1;
|
||
|
}
|
||
|
d->bufp = d->buf;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
flushimage(Display *d, int visible)
|
||
|
{
|
||
|
if(visible){
|
||
|
*d->bufp++ = 'v'; /* five bytes always reserved for this */
|
||
|
if(d->_isnewdisplay){
|
||
|
BPLONG(d->bufp, d->screenimage->id);
|
||
|
d->bufp += 4;
|
||
|
}
|
||
|
}
|
||
|
return doflush(d);
|
||
|
}
|
||
|
|
||
|
uchar*
|
||
|
bufimage(Display *d, int n)
|
||
|
{
|
||
|
uchar *p;
|
||
|
|
||
|
if(n<0 || n>d->bufsize){
|
||
|
abort();
|
||
|
werrstr("bad count in bufimage");
|
||
|
return 0;
|
||
|
}
|
||
|
if(d->bufp+n > d->buf+d->bufsize)
|
||
|
if(doflush(d) < 0)
|
||
|
return 0;
|
||
|
p = d->bufp;
|
||
|
d->bufp += n;
|
||
|
return p;
|
||
|
}
|
||
|
|