vt: implement /dev/cons and /dev/consctl as a fileserver, winch, incremental redraw
we used to bind a pipe to /dev/cons and /dev/consctl with some shared segment hack to pass tty info arround. now we implement this as a fileserver. add support for "winchon"/"winchoff" ctl message to enable interrupt on window size change. (used by ssh) keep track of fullscreen scrolls, avoiding redrawing the whole screen each time.
This commit is contained in:
parent
bc54898807
commit
b28c3db578
|
@ -3,10 +3,17 @@ typedef struct Consstate Consstate;
|
||||||
struct Consstate{
|
struct Consstate{
|
||||||
int raw;
|
int raw;
|
||||||
int hold;
|
int hold;
|
||||||
|
int winch;
|
||||||
};
|
};
|
||||||
|
extern Consstate cs[];
|
||||||
|
|
||||||
extern Consstate* consctl(void);
|
typedef struct Buf Buf;
|
||||||
extern Consstate* cs;
|
struct Buf
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
char *s;
|
||||||
|
char b[];
|
||||||
|
};
|
||||||
|
|
||||||
#define INSET 2
|
#define INSET 2
|
||||||
#define BUFS 32
|
#define BUFS 32
|
||||||
|
@ -75,4 +82,4 @@ extern int cursoron;
|
||||||
extern int nocolor;
|
extern int nocolor;
|
||||||
|
|
||||||
extern void setdim(int, int);
|
extern void setdim(int, int);
|
||||||
|
extern void mountcons(void);
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
#include <u.h>
|
|
||||||
#include <libc.h>
|
|
||||||
#include <draw.h>
|
|
||||||
#include "cons.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* bind a pipe onto consctl and keep reading it to
|
|
||||||
* get changes to console state.
|
|
||||||
*/
|
|
||||||
Consstate*
|
|
||||||
consctl(void)
|
|
||||||
{
|
|
||||||
int i, n, fd, tries;
|
|
||||||
char buf[128];
|
|
||||||
Consstate *x;
|
|
||||||
char *field[10];
|
|
||||||
|
|
||||||
x = segattach(0, "shared", 0, sizeof *x);
|
|
||||||
if(x == (void*)-1)
|
|
||||||
sysfatal("segattach: %r");
|
|
||||||
|
|
||||||
/* a pipe to simulate consctl */
|
|
||||||
if(bind("#|", "/mnt/consctl", MBEFORE) < 0
|
|
||||||
|| bind("/mnt/consctl/data1", "/dev/consctl", MREPL) < 0)
|
|
||||||
sysfatal("bind consctl: %r");
|
|
||||||
|
|
||||||
/* a pipe to simulate the /dev/cons */
|
|
||||||
if(bind("#|", "/mnt/cons", MREPL) < 0
|
|
||||||
|| bind("/mnt/cons/data1", "/dev/cons", MREPL) < 0)
|
|
||||||
sysfatal("bind cons: %r");
|
|
||||||
|
|
||||||
switch(fork()){
|
|
||||||
case -1:
|
|
||||||
sysfatal("fork: %r");
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
notify(0);
|
|
||||||
|
|
||||||
for(tries = 0; tries < 100; tries++){
|
|
||||||
x->raw = 0;
|
|
||||||
x->hold = 0;
|
|
||||||
fd = open("/mnt/consctl/data", OREAD);
|
|
||||||
if(fd < 0)
|
|
||||||
break;
|
|
||||||
tries = 0;
|
|
||||||
for(;;){
|
|
||||||
n = read(fd, buf, sizeof(buf)-1);
|
|
||||||
if(n <= 0)
|
|
||||||
break;
|
|
||||||
buf[n] = 0;
|
|
||||||
n = getfields(buf, field, 10, 1, " ");
|
|
||||||
for(i = 0; i < n; i++){
|
|
||||||
if(strcmp(field[i], "rawon") == 0)
|
|
||||||
x->raw = 1;
|
|
||||||
else if(strcmp(field[i], "rawoff") == 0)
|
|
||||||
x->raw = 0;
|
|
||||||
else if(strcmp(field[i], "holdon") == 0)
|
|
||||||
x->hold = 1;
|
|
||||||
else if(strcmp(field[i], "holdoff") == 0)
|
|
||||||
x->hold = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
exits(0);
|
|
||||||
return 0; /* dummy to keep compiler quiet*/
|
|
||||||
}
|
|
213
sys/src/cmd/vt/fs.c
Normal file
213
sys/src/cmd/vt/fs.c
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <draw.h>
|
||||||
|
|
||||||
|
#include "cons.h"
|
||||||
|
|
||||||
|
#include <thread.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <9p.h>
|
||||||
|
|
||||||
|
extern Channel *hc[2];
|
||||||
|
|
||||||
|
static File *devcons, *devconsctl;
|
||||||
|
|
||||||
|
static Channel *readreq;
|
||||||
|
static Channel *flushreq;
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsreader(void*)
|
||||||
|
{
|
||||||
|
Req *r, *fr;
|
||||||
|
Buf *b;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
b = nil;
|
||||||
|
r = nil;
|
||||||
|
for(;;){
|
||||||
|
Alt a[] = {
|
||||||
|
{ flushreq, &fr, CHANRCV },
|
||||||
|
{ readreq, &r, r == nil ? CHANRCV : CHANNOP },
|
||||||
|
{ hc[0], &b, b == nil ? CHANRCV : CHANNOP },
|
||||||
|
{ nil, nil, b == nil || r == nil ? CHANEND : CHANNOBLK },
|
||||||
|
};
|
||||||
|
if(alt(a) == 0){
|
||||||
|
if(fr->oldreq == r){
|
||||||
|
respond(r, "interrupted");
|
||||||
|
r = nil;
|
||||||
|
}
|
||||||
|
respond(fr, nil);
|
||||||
|
}
|
||||||
|
if(b == nil || r == nil)
|
||||||
|
continue;
|
||||||
|
r->ofcall.count = 0;
|
||||||
|
while((n = r->ifcall.count - r->ofcall.count) > 0){
|
||||||
|
if(n > b->n)
|
||||||
|
n = b->n;
|
||||||
|
memmove((char*)r->ofcall.data + r->ofcall.count, b->s, n);
|
||||||
|
r->ofcall.count += n;
|
||||||
|
b->s += n, b->n -= n;
|
||||||
|
if(b->n <= 0){
|
||||||
|
free(b);
|
||||||
|
if((b = nbrecvp(hc[0])) == nil)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
respond(r, nil);
|
||||||
|
r = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsread(Req *r)
|
||||||
|
{
|
||||||
|
if(r->fid->file == devcons){
|
||||||
|
sendp(readreq, r);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
respond(r, "not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct Partutf Partutf;
|
||||||
|
struct Partutf
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
char s[UTFmax];
|
||||||
|
};
|
||||||
|
|
||||||
|
static Rune*
|
||||||
|
cvtc2r(char *b, int n, Partutf *u)
|
||||||
|
{
|
||||||
|
char *cp, *ep;
|
||||||
|
Rune *rp, *rb;
|
||||||
|
|
||||||
|
cp = b, ep = b + n;
|
||||||
|
rp = rb = emalloc9p(sizeof(Rune)*(n+2));
|
||||||
|
|
||||||
|
while(u->n > 0 && cp < ep){
|
||||||
|
u->s[u->n++] = *cp++;
|
||||||
|
if(fullrune(u->s, u->n)){
|
||||||
|
chartorune(rp, u->s);
|
||||||
|
if(*rp != 0)
|
||||||
|
rp++;
|
||||||
|
u->n = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(u->n == 0){
|
||||||
|
while(cp < ep && fullrune(cp, ep - cp)){
|
||||||
|
cp += chartorune(rp, cp);
|
||||||
|
if(*rp != 0)
|
||||||
|
rp++;
|
||||||
|
}
|
||||||
|
n = ep - cp;
|
||||||
|
if(n > 0){
|
||||||
|
memmove(u->s, cp, n);
|
||||||
|
u->n = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(rb == rp){
|
||||||
|
free(rb);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
*rp = 0;
|
||||||
|
|
||||||
|
return rb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fswrite(Req *r)
|
||||||
|
{
|
||||||
|
if(r->fid->file == devcons){
|
||||||
|
Partutf *u;
|
||||||
|
Rune *rp;
|
||||||
|
|
||||||
|
if((u = r->fid->aux) == nil)
|
||||||
|
u = r->fid->aux = emalloc9p(sizeof(*u));
|
||||||
|
if((rp = cvtc2r((char*)r->ifcall.data, r->ifcall.count, u)) != nil)
|
||||||
|
sendp(hc[1], rp);
|
||||||
|
|
||||||
|
r->ofcall.count = r->ifcall.count;
|
||||||
|
respond(r, nil);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(r->fid->file == devconsctl){
|
||||||
|
char *s = r->ifcall.data;
|
||||||
|
int n = r->ifcall.count;
|
||||||
|
|
||||||
|
if(n >= 5 && strncmp(s, "rawon", 5) == 0)
|
||||||
|
cs->raw = 1;
|
||||||
|
else if(n >= 6 && strncmp(s, "rawoff", 6) == 0)
|
||||||
|
cs->raw = 0;
|
||||||
|
else if(n >= 6 && strncmp(s, "holdon", 6) == 0)
|
||||||
|
cs->hold = 1;
|
||||||
|
else if(n >= 7 && strncmp(s, "holdoff", 7) == 0)
|
||||||
|
cs->hold = 0;
|
||||||
|
else if(n >= 7 && strncmp(s, "winchon", 7) == 0)
|
||||||
|
cs->winch = 1;
|
||||||
|
else if(n >= 8 && strncmp(s, "winchoff", 8) == 0)
|
||||||
|
cs->winch = 0;
|
||||||
|
|
||||||
|
r->ofcall.count = r->ifcall.count;
|
||||||
|
respond(r, nil);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
respond(r, "not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsflush(Req *r)
|
||||||
|
{
|
||||||
|
sendp(flushreq, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsdestroyfid(Fid *f)
|
||||||
|
{
|
||||||
|
if(f->file == devconsctl && f->omode >= 0){
|
||||||
|
cs->raw = 0;
|
||||||
|
cs->hold = 0;
|
||||||
|
cs->winch = 0;
|
||||||
|
}
|
||||||
|
if(f->aux != nil){
|
||||||
|
free(f->aux);
|
||||||
|
f->aux = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsstart(Srv*)
|
||||||
|
{
|
||||||
|
flushreq = chancreate(sizeof(Req*), 4);
|
||||||
|
readreq = chancreate(sizeof(Req*), 4);
|
||||||
|
proccreate(fsreader, nil, 16*1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsend(Srv*)
|
||||||
|
{
|
||||||
|
sendp(hc[1], nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
Srv fs = {
|
||||||
|
.read=fsread,
|
||||||
|
.write=fswrite,
|
||||||
|
.flush=fsflush,
|
||||||
|
.destroyfid=fsdestroyfid,
|
||||||
|
.start=fsstart,
|
||||||
|
.end=fsend,
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
mountcons(void)
|
||||||
|
{
|
||||||
|
fs.tree = alloctree("vt", "vt", DMDIR|0555, nil);
|
||||||
|
devcons = createfile(fs.tree->root, "cons", "vt", 0666, nil);
|
||||||
|
if(devcons == nil)
|
||||||
|
sysfatal("creating /dev/cons: %r");
|
||||||
|
devconsctl = createfile(fs.tree->root, "consctl", "vt", 0666, nil);
|
||||||
|
if(devconsctl == nil)
|
||||||
|
sysfatal("creating /dev/consctl: %r");
|
||||||
|
threadpostmountsrv(&fs, nil, "/dev", MBEFORE);
|
||||||
|
}
|
|
@ -1,11 +1,16 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <draw.h>
|
#include <draw.h>
|
||||||
|
|
||||||
|
#include "cons.h"
|
||||||
|
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <9p.h>
|
||||||
|
|
||||||
|
#include <bio.h>
|
||||||
#include <mouse.h>
|
#include <mouse.h>
|
||||||
#include <keyboard.h>
|
#include <keyboard.h>
|
||||||
#include <bio.h>
|
|
||||||
#include "cons.h"
|
|
||||||
|
|
||||||
char *menutext2[] = {
|
char *menutext2[] = {
|
||||||
"backup",
|
"backup",
|
||||||
|
@ -40,6 +45,7 @@ int pagemode;
|
||||||
int olines;
|
int olines;
|
||||||
int peekc;
|
int peekc;
|
||||||
int cursoron = 1;
|
int cursoron = 1;
|
||||||
|
int hostclosed = 0;
|
||||||
Menu menu2;
|
Menu menu2;
|
||||||
Menu menu3;
|
Menu menu3;
|
||||||
Rune *histp;
|
Rune *histp;
|
||||||
|
@ -52,9 +58,15 @@ uchar *onscreencbuf;
|
||||||
#define onscreena(x, y) &onscreenabuf[((y)*(xmax+2) + (x))]
|
#define onscreena(x, y) &onscreenabuf[((y)*(xmax+2) + (x))]
|
||||||
#define onscreenc(x, y) &onscreencbuf[((y)*(xmax+2) + (x))]
|
#define onscreenc(x, y) &onscreencbuf[((y)*(xmax+2) + (x))]
|
||||||
|
|
||||||
|
uchar *screenchangebuf;
|
||||||
|
uint scrolloff;
|
||||||
|
|
||||||
|
#define screenchange(y) screenchangebuf[((y)+scrolloff) % (ymax+1)]
|
||||||
|
|
||||||
int yscrmin, yscrmax;
|
int yscrmin, yscrmax;
|
||||||
int attr, defattr;
|
int attr, defattr;
|
||||||
|
|
||||||
|
Image *cursorsave;
|
||||||
Image *bordercol;
|
Image *bordercol;
|
||||||
Image *colors[8];
|
Image *colors[8];
|
||||||
Image *hicolors[8];
|
Image *hicolors[8];
|
||||||
|
@ -100,13 +112,12 @@ Rune kbdchar;
|
||||||
|
|
||||||
Mousectl *mc;
|
Mousectl *mc;
|
||||||
Keyboardctl *kc;
|
Keyboardctl *kc;
|
||||||
Channel *hc;
|
Channel *hc[2];
|
||||||
Consstate *cs;
|
Consstate cs[1];
|
||||||
|
|
||||||
int nocolor;
|
int nocolor;
|
||||||
int logfd = -1;
|
int logfd = -1;
|
||||||
int hostfd = -1;
|
int hostpid = -1;
|
||||||
int hostpid;
|
|
||||||
Biobuf *snarffp = 0;
|
Biobuf *snarffp = 0;
|
||||||
Rune *hostbuf, *hostbufp;
|
Rune *hostbuf, *hostbufp;
|
||||||
char echo_input[BSIZE];
|
char echo_input[BSIZE];
|
||||||
|
@ -118,7 +129,6 @@ char *term;
|
||||||
struct funckey *fk, *appfk;
|
struct funckey *fk, *appfk;
|
||||||
|
|
||||||
/* functions */
|
/* functions */
|
||||||
void initialize(int, char **);
|
|
||||||
int waitchar(void);
|
int waitchar(void);
|
||||||
void waitio(void);
|
void waitio(void);
|
||||||
int rcvchar(void);
|
int rcvchar(void);
|
||||||
|
@ -130,78 +140,62 @@ void send_interrupt(void);
|
||||||
int alnum(int);
|
int alnum(int);
|
||||||
void escapedump(int,uchar *,int);
|
void escapedump(int,uchar *,int);
|
||||||
|
|
||||||
int
|
static Channel *pidchan;
|
||||||
start_host(void)
|
|
||||||
|
static void
|
||||||
|
runcmd(void *args)
|
||||||
{
|
{
|
||||||
switch((hostpid = rfork(RFPROC|RFNAMEG|RFFDG|RFNOTEG))) {
|
char **argv = args;
|
||||||
case 0:
|
char *cmd;
|
||||||
close(0);
|
|
||||||
open("/dev/cons", OREAD);
|
rfork(RFNAMEG);
|
||||||
close(1);
|
mountcons();
|
||||||
open("/dev/cons", OWRITE);
|
|
||||||
dup(1, 2);
|
rfork(RFFDG);
|
||||||
execl("/bin/rc","rcX",nil);
|
close(0);
|
||||||
fprint(2, "failed to start up rc: %r\n");
|
open("/dev/cons", OREAD);
|
||||||
_exits("rc");
|
close(1);
|
||||||
case -1:
|
open("/dev/cons", OWRITE);
|
||||||
fprint(2,"rc startup: fork: %r\n");
|
dup(1, 2);
|
||||||
_exits("rc_fork");
|
|
||||||
|
cmd = nil;
|
||||||
|
while(*argv != nil){
|
||||||
|
if(cmd == nil)
|
||||||
|
cmd = strdup(*argv);
|
||||||
|
else
|
||||||
|
cmd = smprint("%s %q", cmd, *argv);
|
||||||
|
argv++;
|
||||||
}
|
}
|
||||||
return open("/mnt/cons/data", ORDWR);
|
|
||||||
|
procexecl(pidchan, "/bin/rc", "rcX", cmd == nil ? nil : "-c", cmd, nil);
|
||||||
|
sysfatal("%r");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
send_interrupt(void)
|
send_interrupt(void)
|
||||||
{
|
{
|
||||||
postnote(PNGROUP, hostpid, "interrupt");
|
if(hostpid > 0)
|
||||||
|
postnote(PNGROUP, hostpid, "interrupt");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
hostreader(void*)
|
sendnchars(int n, char *p)
|
||||||
{
|
{
|
||||||
char cb[BSIZE+1], *cp;
|
Buf *b;
|
||||||
Rune *rb, *rp;
|
|
||||||
int n, r;
|
|
||||||
|
|
||||||
n = 0;
|
b = emalloc9p(sizeof(Buf)+n);
|
||||||
while((r = read(hostfd, cb+n, BSIZE-n)) > 0){
|
memmove(b->s = b->b, p, b->n = n);
|
||||||
n += r;
|
if(nbsendp(hc[0], b) < 0)
|
||||||
rb = mallocz((n+1)*sizeof(Rune), 0);
|
free(b);
|
||||||
for(rp = rb, cp = cb; n > 0; n -= r, cp += r){
|
|
||||||
if(!fullrune(cp, n))
|
|
||||||
break;
|
|
||||||
r = chartorune(rp, cp);
|
|
||||||
if(*rp != 0)
|
|
||||||
rp++;
|
|
||||||
}
|
|
||||||
if(rp > rb){
|
|
||||||
*rp = 0;
|
|
||||||
sendp(hc, rb);
|
|
||||||
} else {
|
|
||||||
free(rb);
|
|
||||||
}
|
|
||||||
if(n > 0) memmove(cb, cp, n);
|
|
||||||
}
|
|
||||||
sendp(hc, nil);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
shutdown(void)
|
shutdown(void)
|
||||||
{
|
{
|
||||||
send_interrupt();
|
send_interrupt();
|
||||||
postnote(PNGROUP, getpid(), "exit");
|
|
||||||
threadexitsall(nil);
|
threadexitsall(nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
threadmain(int argc, char **argv)
|
|
||||||
{
|
|
||||||
rfork(RFNAMEG|RFNOTEG|RFENVG);
|
|
||||||
atexit(shutdown);
|
|
||||||
initialize(argc, argv);
|
|
||||||
emulate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
|
@ -210,7 +204,7 @@ usage(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
initialize(int argc, char **argv)
|
threadmain(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int rflag;
|
int rflag;
|
||||||
int i, blkbg;
|
int i, blkbg;
|
||||||
|
@ -257,14 +251,19 @@ initialize(int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
}ARGEND;
|
}ARGEND;
|
||||||
|
|
||||||
|
quotefmtinstall();
|
||||||
|
atexit(shutdown);
|
||||||
|
|
||||||
if(initdraw(0, fontname, term) < 0)
|
if(initdraw(0, fontname, term) < 0)
|
||||||
sysfatal("inidraw failed: %r");
|
sysfatal("inidraw failed: %r");
|
||||||
if((mc = initmouse("/dev/mouse", screen)) == nil)
|
if((mc = initmouse("/dev/mouse", screen)) == nil)
|
||||||
sysfatal("initmouse failed: %r");
|
sysfatal("initmouse failed: %r");
|
||||||
if((kc = initkeyboard("/dev/cons")) == nil)
|
if((kc = initkeyboard("/dev/cons")) == nil)
|
||||||
sysfatal("initkeyboard failed: %r");
|
sysfatal("initkeyboard failed: %r");
|
||||||
if((cs = consctl()) == nil)
|
|
||||||
sysfatal("consctl failed: %r");
|
hc[0] = chancreate(sizeof(Buf*), 8); /* input to host */
|
||||||
|
hc[1] = chancreate(sizeof(Rune*), 8); /* output from host */
|
||||||
|
|
||||||
cs->raw = rflag;
|
cs->raw = rflag;
|
||||||
|
|
||||||
histp = hist;
|
histp = hist;
|
||||||
|
@ -290,19 +289,11 @@ initialize(int argc, char **argv)
|
||||||
fgcolor = (blkbg? display->white: display->black);
|
fgcolor = (blkbg? display->white: display->black);
|
||||||
resize();
|
resize();
|
||||||
|
|
||||||
hc = chancreate(sizeof(Rune*), 5);
|
pidchan = chancreate(sizeof(int), 0);
|
||||||
if((hostfd = start_host()) >= 0)
|
proccreate(runcmd, argv, 16*1024);
|
||||||
proccreate(hostreader, nil, BSIZE+1024);
|
hostpid = recvul(pidchan);
|
||||||
|
|
||||||
while(*argv != nil){
|
emulate();
|
||||||
sendnchars(strlen(*argv), *argv);
|
|
||||||
if(argv[1] == nil){
|
|
||||||
sendnchars(1, "\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sendnchars(1, " ");
|
|
||||||
argv++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Image*
|
Image*
|
||||||
|
@ -333,6 +324,16 @@ fgcol(int a, int c)
|
||||||
return colors[(c>>1)&7];
|
return colors[(c>>1)&7];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hidecursor(void)
|
||||||
|
{
|
||||||
|
if(cursorsave == nil)
|
||||||
|
return;
|
||||||
|
draw(screen, cursorsave->r, cursorsave, nil, cursorsave->r.min);
|
||||||
|
freeimage(cursorsave);
|
||||||
|
cursorsave = nil;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
drawscreen(void)
|
drawscreen(void)
|
||||||
{
|
{
|
||||||
|
@ -342,26 +343,28 @@ drawscreen(void)
|
||||||
Rune *rp;
|
Rune *rp;
|
||||||
Point p, q;
|
Point p, q;
|
||||||
|
|
||||||
draw(screen, screen->r, bgcolor, nil, ZP);
|
hidecursor();
|
||||||
|
|
||||||
|
if(scrolloff != 0){
|
||||||
|
n = scrolloff % (ymax+1);
|
||||||
|
draw(screen, Rpt(pt(0,0), pt(xmax+2, ymax+1-n)), screen, nil, pt(0, n));
|
||||||
|
}
|
||||||
|
|
||||||
/* draw background */
|
|
||||||
for(y = 0; y <= ymax; y++){
|
for(y = 0; y <= ymax; y++){
|
||||||
|
if(!screenchange(y))
|
||||||
|
continue;
|
||||||
|
screenchange(y) = 0;
|
||||||
|
|
||||||
for(x = 0; x <= xmax; x += n){
|
for(x = 0; x <= xmax; x += n){
|
||||||
cp = onscreenc(x, y);
|
cp = onscreenc(x, y);
|
||||||
ap = onscreena(x, y);
|
ap = onscreena(x, y);
|
||||||
c = bgcol(*ap, *cp);
|
c = bgcol(*ap, *cp);
|
||||||
if(c == bgcolor){
|
|
||||||
n = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for(n = 1; x+n <= xmax && bgcol(ap[n], cp[n]) == c; n++)
|
for(n = 1; x+n <= xmax && bgcol(ap[n], cp[n]) == c; n++)
|
||||||
;
|
;
|
||||||
draw(screen, Rpt(pt(x, y), pt(x+n, y+1)), c, nil, ZP);
|
draw(screen, Rpt(pt(x, y), pt(x+n, y+1)), c, nil, ZP);
|
||||||
}
|
}
|
||||||
}
|
draw(screen, Rpt(pt(x, y), pt(x+1, y+1)), bgcolor, nil, ZP);
|
||||||
|
|
||||||
/* draw foreground */
|
|
||||||
for(y = 0; y <= ymax; y++){
|
|
||||||
for(x = 0; x <= xmax; x += n){
|
for(x = 0; x <= xmax; x += n){
|
||||||
rp = onscreenr(x, y);
|
rp = onscreenr(x, y);
|
||||||
if(*rp == 0){
|
if(*rp == 0){
|
||||||
|
@ -387,25 +390,40 @@ drawscreen(void)
|
||||||
bordercol,
|
bordercol,
|
||||||
ZP, font, L">", 1);
|
ZP, font, L">", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scrolloff = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
drawcursor(void)
|
drawcursor(void)
|
||||||
{
|
{
|
||||||
Image *col;
|
Image *col;
|
||||||
|
Rectangle r;
|
||||||
|
|
||||||
|
hidecursor();
|
||||||
if(cursoron == 0)
|
if(cursoron == 0)
|
||||||
return;
|
return;
|
||||||
col = (blocked || hostfd < 0) ? red : bordercol;
|
|
||||||
border(screen, Rpt(pt(x, y), pt(x+1, y+1)), 2, col, ZP);
|
col = (blocked || hostclosed) ? red : bordercol;
|
||||||
|
r = Rpt(pt(x, y), pt(x+1, y+1));
|
||||||
|
|
||||||
|
cursorsave = allocimage(display, r, screen->chan, 0, DNofill);
|
||||||
|
draw(cursorsave, r, screen, nil, r.min);
|
||||||
|
|
||||||
|
border(screen, r, 2, col, ZP);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
clear(int x1, int y1, int x2, int y2)
|
clear(int x1, int y1, int x2, int y2)
|
||||||
{
|
{
|
||||||
int c = (attr & 0x0F00)>>8; /* bgcolor */
|
int c = (attr & 0x0F00)>>8; /* bgcolor */
|
||||||
|
|
||||||
|
if(y1 < 0 || y1 > ymax || x1 < 0 || x1 > xmax || y2 <= y1 || x2 <= x1)
|
||||||
|
return;
|
||||||
|
|
||||||
while(y1 < y2){
|
while(y1 < y2){
|
||||||
|
screenchange(y1) = 1;
|
||||||
if(x1 < x2){
|
if(x1 < x2){
|
||||||
memset(onscreenr(x1, y1), 0, (x2-x1)*sizeof(Rune));
|
memset(onscreenr(x1, y1), 0, (x2-x1)*sizeof(Rune));
|
||||||
memset(onscreena(x1, y1), 0, x2-x1);
|
memset(onscreena(x1, y1), 0, x2-x1);
|
||||||
|
@ -713,8 +731,8 @@ waitchar(void)
|
||||||
if(host_avail())
|
if(host_avail())
|
||||||
return(rcvchar());
|
return(rcvchar());
|
||||||
free(hostbuf);
|
free(hostbuf);
|
||||||
hostbufp = hostbuf = nbrecvp(hc);
|
hostbufp = hostbuf = nbrecvp(hc[1]);
|
||||||
if(host_avail() && nrand(8))
|
if(host_avail() && nrand(32))
|
||||||
return(rcvchar());
|
return(rcvchar());
|
||||||
}
|
}
|
||||||
drawscreen();
|
drawscreen();
|
||||||
|
@ -731,7 +749,7 @@ waitio(void)
|
||||||
{ mc->c, &mc->Mouse, CHANRCV },
|
{ mc->c, &mc->Mouse, CHANRCV },
|
||||||
{ mc->resizec, nil, CHANRCV },
|
{ mc->resizec, nil, CHANRCV },
|
||||||
{ kc->c, &kbdchar, CHANRCV },
|
{ kc->c, &kbdchar, CHANRCV },
|
||||||
{ hc, &hostbuf, CHANRCV },
|
{ hc[1], &hostbuf, CHANRCV },
|
||||||
{ nil, nil, CHANEND },
|
{ nil, nil, CHANEND },
|
||||||
};
|
};
|
||||||
if(blocked)
|
if(blocked)
|
||||||
|
@ -755,10 +773,8 @@ Next:
|
||||||
break;
|
break;
|
||||||
case AHOST:
|
case AHOST:
|
||||||
hostbufp = hostbuf;
|
hostbufp = hostbuf;
|
||||||
if(hostbuf == nil){
|
if(hostbuf == nil)
|
||||||
close(hostfd);
|
hostclosed = 1;
|
||||||
hostfd = -1;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -780,6 +796,8 @@ exportsize(void)
|
||||||
putenvint("LINES", ymax+1);
|
putenvint("LINES", ymax+1);
|
||||||
putenvint("COLS", xmax+1);
|
putenvint("COLS", xmax+1);
|
||||||
putenv("TERM", term);
|
putenv("TERM", term);
|
||||||
|
if(cs->winch)
|
||||||
|
send_interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -799,14 +817,20 @@ setdim(int ht, int wid)
|
||||||
margin.x = (Dx(screen->r) - (xmax+1)*ftsize.x) / 2;
|
margin.x = (Dx(screen->r) - (xmax+1)*ftsize.x) / 2;
|
||||||
margin.y = (Dy(screen->r) - (ymax+1)*ftsize.y) / 2;
|
margin.y = (Dy(screen->r) - (ymax+1)*ftsize.y) / 2;
|
||||||
|
|
||||||
|
free(screenchangebuf);
|
||||||
|
screenchangebuf = emalloc9p(ymax+1);
|
||||||
|
scrolloff = 0;
|
||||||
|
|
||||||
free(onscreenrbuf);
|
free(onscreenrbuf);
|
||||||
onscreenrbuf = mallocz((ymax+1)*(xmax+2)*sizeof(Rune), 1);
|
onscreenrbuf = emalloc9p((ymax+1)*(xmax+2)*sizeof(Rune));
|
||||||
free(onscreenabuf);
|
free(onscreenabuf);
|
||||||
onscreenabuf = mallocz((ymax+1)*(xmax+2), 1);
|
onscreenabuf = emalloc9p((ymax+1)*(xmax+2));
|
||||||
free(onscreencbuf);
|
free(onscreencbuf);
|
||||||
onscreencbuf = mallocz((ymax+1)*(xmax+2), 1);
|
onscreencbuf = emalloc9p((ymax+1)*(xmax+2));
|
||||||
clear(0,0,xmax+1,ymax+1);
|
clear(0,0,xmax+1,ymax+1);
|
||||||
|
|
||||||
|
draw(screen, screen->r, bgcolor, nil, ZP);
|
||||||
|
|
||||||
if(resize_flag || backc)
|
if(resize_flag || backc)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1052,10 +1076,15 @@ pos(Point pt)
|
||||||
void
|
void
|
||||||
shift(int x1, int y, int x2, int w)
|
shift(int x1, int y, int x2, int w)
|
||||||
{
|
{
|
||||||
|
if(y < 0 || y > ymax || x1 < 0 || x2 < 0 || w <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
if(x1+w > xmax+1)
|
if(x1+w > xmax+1)
|
||||||
w = xmax+1 - x1;
|
w = xmax+1 - x1;
|
||||||
if(x2+w > xmax+1)
|
if(x2+w > xmax+1)
|
||||||
w = xmax+1 - x2;
|
w = xmax+1 - x2;
|
||||||
|
|
||||||
|
screenchange(y) = 1;
|
||||||
memmove(onscreenr(x1, y), onscreenr(x2, y), w*sizeof(Rune));
|
memmove(onscreenr(x1, y), onscreenr(x2, y), w*sizeof(Rune));
|
||||||
memmove(onscreena(x1, y), onscreena(x2, y), w);
|
memmove(onscreena(x1, y), onscreena(x2, y), w);
|
||||||
memmove(onscreenc(x1, y), onscreenc(x2, y), w);
|
memmove(onscreenc(x1, y), onscreenc(x2, y), w);
|
||||||
|
@ -1064,9 +1093,30 @@ shift(int x1, int y, int x2, int w)
|
||||||
void
|
void
|
||||||
scroll(int sy, int ly, int dy, int cy) /* source, limit, dest, which line to clear */
|
scroll(int sy, int ly, int dy, int cy) /* source, limit, dest, which line to clear */
|
||||||
{
|
{
|
||||||
memmove(onscreenr(0, dy), onscreenr(0, sy), (ly-sy)*(xmax+2)*sizeof(Rune));
|
int n, d, i;
|
||||||
memmove(onscreena(0, dy), onscreena(0, sy), (ly-sy)*(xmax+2));
|
|
||||||
memmove(onscreenc(0, dy), onscreenc(0, sy), (ly-sy)*(xmax+2));
|
if(sy < 0 || sy > ymax || dy < 0 || dy > ymax)
|
||||||
|
return;
|
||||||
|
|
||||||
|
n = ly - sy;
|
||||||
|
if(sy + n > ymax+1)
|
||||||
|
n = ymax+1 - sy;
|
||||||
|
if(dy + n > ymax+1)
|
||||||
|
n = ymax+1 - dy;
|
||||||
|
|
||||||
|
d = sy - dy;
|
||||||
|
if(n > 0 && d != 0){
|
||||||
|
if(d > 0 && dy == 0 && n >= ymax){
|
||||||
|
scrolloff += d;
|
||||||
|
} else {
|
||||||
|
for(i = 0; i < n; i++)
|
||||||
|
screenchange(dy+i) = 1;
|
||||||
|
}
|
||||||
|
memmove(onscreenr(0, dy), onscreenr(0, sy), n*(xmax+2)*sizeof(Rune));
|
||||||
|
memmove(onscreena(0, dy), onscreena(0, sy), n*(xmax+2));
|
||||||
|
memmove(onscreenc(0, dy), onscreenc(0, sy), n*(xmax+2));
|
||||||
|
}
|
||||||
|
|
||||||
clear(0, cy, xmax+1, cy+1);
|
clear(0, cy, xmax+1, cy+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1079,13 +1129,13 @@ bigscroll(void) /* scroll up half a page */
|
||||||
return;
|
return;
|
||||||
if(y < half) {
|
if(y < half) {
|
||||||
clear(0, 0, xmax+1, ymax+1);
|
clear(0, 0, xmax+1, ymax+1);
|
||||||
|
scrolloff = 0;
|
||||||
x = y = 0;
|
x = y = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memmove(onscreenr(0, 0), onscreenr(0, half), (ymax-half+1)*(xmax+2)*sizeof(Rune));
|
scroll(half, ymax+1, 0, ymax);
|
||||||
memmove(onscreena(0, 0), onscreena(0, half), (ymax-half+1)*(xmax+2));
|
|
||||||
memmove(onscreenc(0, 0), onscreenc(0, half), (ymax-half+1)*(xmax+2));
|
|
||||||
clear(0, y-half+1, xmax+1, ymax+1);
|
clear(0, y-half+1, xmax+1, ymax+1);
|
||||||
|
|
||||||
y -= half;
|
y -= half;
|
||||||
if(olines)
|
if(olines)
|
||||||
olines -= half;
|
olines -= half;
|
||||||
|
@ -1109,17 +1159,6 @@ number(Rune *p, int *got)
|
||||||
|
|
||||||
/* stubs */
|
/* stubs */
|
||||||
|
|
||||||
void
|
|
||||||
sendnchars(int n,char *p)
|
|
||||||
{
|
|
||||||
if(hostfd < 0)
|
|
||||||
return;
|
|
||||||
if(write(hostfd,p,n) < 0){
|
|
||||||
close(hostfd);
|
|
||||||
hostfd = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
host_avail(void)
|
host_avail(void)
|
||||||
{
|
{
|
||||||
|
@ -1179,6 +1218,7 @@ escapedump(int fd,uchar *str,int len)
|
||||||
void
|
void
|
||||||
drawstring(Rune *str, int n)
|
drawstring(Rune *str, int n)
|
||||||
{
|
{
|
||||||
|
screenchange(y) = 1;
|
||||||
memmove(onscreenr(x, y), str, n*sizeof(Rune));
|
memmove(onscreenr(x, y), str, n*sizeof(Rune));
|
||||||
memset(onscreena(x, y), attr & 0xFF, n);
|
memset(onscreena(x, y), attr & 0xFF, n);
|
||||||
memset(onscreenc(x, y), attr >> 8, n);
|
memset(onscreenc(x, y), attr >> 8, n);
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
TARG=vt
|
TARG=vt
|
||||||
|
|
||||||
OFILES=\
|
OFILES=\
|
||||||
consctl.$O\
|
|
||||||
main.$O\
|
main.$O\
|
||||||
vt.$O\
|
vt.$O\
|
||||||
|
fs.$O\
|
||||||
|
|
||||||
HFILES=cons.h
|
HFILES=cons.h
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,11 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <draw.h>
|
#include <draw.h>
|
||||||
#include <bio.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include "cons.h"
|
#include "cons.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
int wraparound = 1;
|
int wraparound = 1;
|
||||||
int originrelative = 0;
|
int originrelative = 0;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue