#include #include #include #define NODEFINE #include <9pm/u.h> #include <9pm/libc.h> #include <9pm/memdraw.h> #include <9pm/cursor.h> #include <9pm/ns.h> #include <9pm/thread.h> #include <9pm/screen.h> static int mousefd; static int cursorfd; static void reshaped(void); static Rectangle screenrect(void) { int fd; char buf[12*5]; fd = open("/dev/screen", OREAD); if(fd == -1) fd = open("/mnt/term/dev/screen", OREAD); if(fd == -1) pm_sysfatal("can't open /dev/screen: %r\n"); if(read(fd, buf, sizeof buf) != sizeof buf) pm_sysfatal("can't read /dev/screen: %r\n"); close(fd); return Rect(atoi(buf+12), atoi(buf+24), atoi(buf+36), atoi(buf+48)); } static int nresize; static void mouseproc(void*) { char buf[50]; char *f[5]; Point p; if((mousefd = open("/dev/mouse", ORDWR)) < 0){ fprint(2, "warning: no mouse\n"); return; } if((cursorfd = open("/dev/cursor", ORDWR)) < 0){ fprint(2, "warning: no cursor\n"); return; } while(read(mousefd, buf, 49) == 49) { if(buf[0] == 'r'){ nresize++; pm_resizescreenimage(); } if(tokenize(buf, f, nelem(f)) < 5) continue; p.x = atoi(f[1]); p.y = atoi(f[2]); p = subpt(p, screen->r.min); pm_mousetrack(p, atoi(f[3]), atoi(f[4])); } } static void kbdproc(void*) { int fd, kfd, n, l; char buf[32], *p; Rune r; if((fd = open("/dev/consctl", OWRITE)) < 0) fprint(2, "warning: cannot set raw mode\n"); else fprint(fd, "rawon"); if((kfd = open("/dev/cons", OREAD)) < 0){ fprint(2, "warning: cannot read /dev/cons\n"); return; } while((n = read(kfd, buf, sizeof buf)) >= 0) { p = buf; while(n > 0) { l = chartorune(&r, p); p += l; n -= l; pm_kbdputc(r); } } } void pm_cursorload(Cursor *c) { char curs[2*4+2*2*16]; if(c == nil) write(cursorfd, curs, 0); else{ BPLONG(curs+0*4, c->offset.x); BPLONG(curs+1*4, c->offset.y); memmove(curs+2*4, c->clr, 2*2*16); write(cursorfd, curs, sizeof curs); } } int pm_cursormove(Point p) { char buf[30]; p = addpt(p, screen->r.min); snprint(buf, sizeof buf, "m%d %d", p.x, p.y); if(write(mousefd, buf, strlen(buf)) != strlen(buf)){ fprint(2, "write %d failed; %r\n", mousefd); abort(); } return 0; /* success? */ } void pm_mousectl(Cmdbuf *c) { USED(c); pm_error("no mouse ctls supported"); } Memimage* pm_attachscreen(int *softscreen) { if(initdraw(0, 0, "drawterm") < 0) sysfatal("plan9 initdraw: %r"); *softscreen = 1; memimageinit(); proccreate(mouseproc, nil, 8192); proccreate(kbdproc, nil, 8192); pm_gscreen = allocmemimage(Rect(0, 0, Dx(screen->r), Dy(screen->r)), screen->chan); if(pm_gscreen == nil) sysfatal("cannot allocate memimage: %r"); pm_drawconsinit(); return pm_gscreen; } void pm_detachscreen(Memimage *m) { USED(m); } Memimage* pm_reattachscreen(Memimage *m, int *softscreen) { *softscreen = 1; if(getwindow(display, Refnone) < 0){ fprint(2,"can't reattach to window"); return m; } m = allocmemimage(Rect(0, 0, Dx(screen->r), Dy(screen->r)), screen->chan); if(m == nil) sysfatal("cannot allocate memimage: %r"); pm_gscreen = m; return m; } #define CHUNK 7500 /* * Like loadimage, but doesn't require the source data to be just the * given rectangle. Lines in data are assumed to be bpl bytes wide. */ static int myloadimage(Image *i, Rectangle r, uchar *data, int ndata, int bpl) { long dy; int n, subbpl, y; uchar *a; if(r.max.x > i->r.max.x) r.max.x = i->r.max.x; if(r.max.y > i->r.max.y) r.max.y = i->r.max.y; if(!rectinrect(r, i->r)){ fprint(2, "myloadimage: bad rectangle\n"); return -1; } subbpl = bytesperline(r, i->depth); n = bpl*(Dy(r)-1)+subbpl; if(n > ndata){ fprint(2, "myloadimage: insufficient data\n"); return -1; } ndata = 0; while(r.max.y > r.min.y){ dy = r.max.y - r.min.y; if(dy*subbpl > CHUNK) dy = CHUNK/subbpl; if(dy <= 0){ fprint(2, "myloadimage: image too wide for buffer (CHUNK=%d, subbpl=%d)\n", CHUNK, subbpl); return -1; } n = dy*subbpl; a = bufimage(i->display, 21+n); if(a == nil){ fprint(2, "myloadimage: bufimage %d failed (dy=%d, subbpl=%d)", 21+n, dy, subbpl); return -1; } a[0] = 'y'; BPLONG(a+1, i->id); BPLONG(a+5, r.min.x); BPLONG(a+9, r.min.y); BPLONG(a+13, r.max.x); BPLONG(a+17, r.min.y+dy); for(y=0; ydisplay, 0) < 0) return -1; return ndata; } void pm_flushmemscreen(Rectangle r) { if(rectclip(&r, pm_gscreen->r) == 0) return; myloadimage(screen, rectaddpt(r, screen->r.min), byteaddr(pm_gscreen, r.min), 1<<30, sizeof(ulong)*pm_gscreen->width); flushimage(display, 1); }