ref: 7c078308937f364f85ca6b79371508127510372f
dir: /samterm/mesg.c/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <thread.h>
#include <cursor.h>
#include <mouse.h>
#include <keyboard.h>
#include <frame.h>
#include <plumb.h>
#include "flayer.h"
#include "samterm.h"
#define HSIZE 3 /* Type + short count */
Header h;
uchar indata[DATASIZE+1]; /* room for NUL */
uchar outdata[DATASIZE];
short outcount;
int hversion;
int exiting;
void inmesg(Hmesg, int);
int inshort(int);
long inlong(int);
vlong invlong(int);
void hsetdot(int, long, long);
void hmoveto(int, long);
void hsetsnarf(int);
void hplumb(int);
void clrlock(void);
int snarfswap(char*, int, char**);
void
rcv(void)
{
int c;
static state = 0;
static count = 0;
static i = 0;
static int errs = 0;
while((c = rcvchar()) != -1)
switch(state){
case 0:
h.type = c;
state++;
break;
case 1:
h.count0 = c;
state++;
break;
case 2:
h.count1 = c;
count = h.count0|(h.count1<<8);
i = 0;
if(count > DATASIZE){
if(++errs < 5){
dumperrmsg(count, h.type, h.count0, c);
state = 0;
continue;
}
fprint(2, "type %d count %d\n", h.type, count);
panic("count>DATASIZE");
}
if(count == 0)
goto zerocount;
state++;
break;
case 3:
indata[i++] = c;
if(i == count){
zerocount:
indata[i] = 0;
inmesg(h.type, count);
state = count = 0;
continue;
}
break;
}
}
Text*
whichtext(int t)
{
int i;
for(i = 0; i < nname; i++)
if(tag[i] == t)
return text[i];
panic("whichtext");
return nil;
}
void
inmesg(Hmesg type, int count)
{
Text *t;
int i, m, w, menu;
long l;
Flayer *lp;
Rune buf[DATASIZE], *r;
int offset;
offset = 0;
m = inshort(0);
menu = whichmenu(m);
l = inlong(2);
switch(type){
case -1:
panic("rcv error");
default:
fprint(2, "type %d\n", type);
panic("rcv unknown");
case Hversion:
hversion = m;
break;
case Hbindname:
l = invlong(2); /* for 64-bit pointers */
if(menu < 0)
break;
/* in case of a race, a bindname may already have occurred */
if(!(t = whichtext(m)))
t = (Text*)l;
else /* let the old one win; clean up the new one */
while(((Text *)l)->nwin>0)
closeup(&((Text *)l)->l[((Text *)l)->front]);
text[menu] = t;
text[menu]->tag = m;
break;
case Hcurrent:
if(menu < 0)
break;
t = whichtext(m);
i = which && ((Text *)which->user1) == &cmd && m != cmd.tag;
if(!t && !(t = sweeptext(0, m)))
break;
if(!t->l[t->front].textfn)
panic("Hcurrent");
lp = &t->l[t->front];
if(i){
flupfront(lp);
flborder(lp, 0);
work = lp;
setmenufile(menu);
}else
current(lp);
break;
case Hmovname:
if(menu < 0)
break;
t = text[menu];
l = tag[menu];
i = name[menu][0];
text[menu] = 0; /* suppress panic in menudel */
menudel(menu);
if(t == &cmd)
menu = 0;
else{
menu = nname > 0 && text[0] == &cmd;
for(; menu < nname; menu++)
if(strcmp((char*)indata+2, (char*)name[menu]+1) < 0)
break;
}
menuins(menu, indata+2, t, i, (int)l);
break;
case Hnewname:
menuins(0, (uchar*)"", nil, ' ', m);
break;
case Hcheck0:
if(menu >= 0){
t = text[menu];
if(t)
t->lock++;
outTs(Tcheck, m);
}
break;
case Hcheck:
if(menu >= 0){
t = text[menu];
if(t && t->lock)
t->lock--;
hcheck(m);
}
break;
case Hunlock:
clrlock();
break;
case Hgrowdata:
case Hgrow:
if(menu < 0)
break;
hgrow(m, l, inlong(6), type == Hgrow);
if(type == Hgrow)
break;
whichtext(m)->lock++;
offset = 10;
case Hdata:
if(menu < 0)
break;
if(!offset)
offset = 6;
r = buf;
for(i = offset; i < count; i += w)
w = chartorune(r++, (char*)indata+i);
l += hdata(m, l, buf, r-buf);
Checkscroll:
if(m == cmd.tag)
for(i = 0; i < NL; i++){
lp = &cmd.l[i];
if(lp->textfn && l > lp->origin+lp->f.nchars)
origin(m, l >= 0? l: lp->p1);
}
break;
case Hunlockfile:
if(menu >= 0 && (t = whichtext(m))->lock){
--t->lock;
l = -1;
goto Checkscroll;
}
break;
case Hsetdot:
if(menu >= 0)
hsetdot(m, l, inlong(6));
break;
case Hmoveto:
if(menu >= 0)
hmoveto(m, l);
break;
case Hclean:
if(menu >= 0)
name[menu][0] = ' ';
break;
case Hdirty:
if(menu >= 0)
name[menu][0] = '\'';
break;
case Hdelname:
if(menu >= 0)
menudel(menu);
break;
case Hcut:
if(menu >= 0)
hcut(m, l, inlong(6));
break;
case Hclose:
if(menu < 0 || !(t = whichtext(m)))
break;
l = t->nwin;
for(i = 0, lp = t->l; l > 0 && i < NL; i++, lp++)
if(lp->textfn){
closeup(lp);
--l;
}
break;
case Hsetpat:
setpat((char*)indata);
break;
case Hsetsnarf:
hsetsnarf(m);
break;
case Hsnarflen:
snarflen = inlong(0);
break;
case Hack:
outT0(Tack);
break;
case Hexit:
exiting = 1;
outT0(Texit);
threadexitsall(nil);
break;
case Hplumb:
hplumb(m);
break;
case Hmenucmd:
menucmd((char*)indata);
break;
}
}
void
setlock(void)
{
hostlock++;
setcursor(mousectl, cursor = &lockarrow);
}
void
clrlock(void)
{
hasunlocked = 1;
if(hostlock > 0)
hostlock--;
if(hostlock == 0)
setcursor(mousectl, cursor = nil);
}
void
startfile(Text *t)
{
outTsv(Tstartfile, t->tag, (vlong)t); /* for 64-bit pointers */
setlock();
}
void
startnewfile(int type, Text *t)
{
t->tag = Untagged;
outTv(type, (vlong)t); /* for 64-bit pointers */
}
int
inshort(int n)
{
return indata[n]|(indata[n+1]<<8);
}
long
inlong(int n)
{
return indata[n]|(indata[n+1]<<8)|
((long)indata[n+2]<<16)|((long)indata[n+3]<<24);
}
vlong
invlong(int n)
{
vlong v;
v = (indata[n+7]<<24) | (indata[n+6]<<16) | (indata[n+5]<<8) | indata[n+4];
v = (v<<16) | (indata[n+3]<<8) | indata[n+2];
v = (v<<16) | (indata[n+1]<<8) | indata[n];
return v;
}
void
outT0(Tmesg type)
{
outstart(type);
outsend();
}
void
outTs(Tmesg type, int s)
{
outstart(type);
outshort(s);
outsend();
}
void
outTss(Tmesg type, int s1, int s2)
{
outstart(type);
outshort(s1);
outshort(s2);
outsend();
}
void
outTsll(Tmesg type, int s1, long l1, long l2)
{
outstart(type);
outshort(s1);
outlong(l1);
outlong(l2);
outsend();
}
void
outTsl(Tmesg type, int s1, long l1)
{
outstart(type);
outshort(s1);
outlong(l1);
outsend();
}
void
outTsv(Tmesg type, int s1, vlong v1)
{
outstart(type);
outshort(s1);
outvlong(v1);
outsend();
}
void
outTv(Tmesg type, vlong v1)
{
outstart(type);
outvlong(v1);
outsend();
}
void
outTslS(Tmesg type, int s1, long l1, Rune *s)
{
char buf[DATASIZE*UTFmax+1];
char *c;
outstart(type);
outshort(s1);
outlong(l1);
c = buf;
while(*s)
c += runetochar(c, s++);
*c++ = 0;
outcopy(c-buf, (uchar *)buf);
outsend();
}
void
outTsls(Tmesg type, int s1, long l1, int s2)
{
outstart(type);
outshort(s1);
outlong(l1);
outshort(s2);
outsend();
}
void
outstart(Tmesg type)
{
outdata[0] = type;
outcount = 0;
}
void
outcopy(int count, uchar *data)
{
while(count--)
outdata[HSIZE+outcount++] = *data++;
}
void
outshort(int s)
{
uchar buf[2];
buf[0] = s;
buf[1] = s >> 8;
outcopy(2, buf);
}
void
outlong(long l)
{
uchar buf[4];
buf[0] = l;
buf[1] = l >> 8;
buf[2] = l >> 16;
buf[3] = l >> 24;
outcopy(4, buf);
}
void
outvlong(vlong v)
{
int i;
uchar buf[8];
for(i = 0; i < sizeof(buf); i++){
buf[i] = v;
v >>= 8;
}
outcopy(8, buf);
}
void
outsend(void)
{
if(outcount > DATASIZE - HSIZE)
panic("outcount > sizeof outdata");
outdata[1] = outcount;
outdata[2] = outcount >> 8;
if(write(1, (char *)outdata, outcount+HSIZE) != outcount+HSIZE)
panic("write error");
}
void
hsetdot(int m, long p0, long p1)
{
Text *t = whichtext(m);
Flayer *l = &t->l[t->front];
flushtyping(1);
flsetselect(l, p0, p1);
}
void
origin(int m, long p)
{
Text *t = whichtext(m);
Flayer *l = &t->l[t->front];
Frame *f = &l->f;
long a;
ulong n;
Rune *r;
p = bound(t, p);
if(!flprepare(l)){
l->origin = p;
return;
}
a = p - l->origin;
if(a >= 0 && a < l->f.nchars)
frdelete(f, 0, a);
else if(a < 0 && -a < l->f.nchars){
r = rload(&t->rasp, p, l->origin, &n);
frinsert(f, r, r+n, 0);
}else
frdelete(f, 0, f->nchars);
l->origin = p;
scrdraw(l, t->rasp.nrunes);
if(l->visible == Some)
flrefresh(l, l->entire, 0);
hcheck(m);
}
void
hmoveto(int m, long p0)
{
Text *t = whichtext(m);
Flayer *l = &t->l[t->front];
if(p0 < l->origin || p0-l->origin > l->f.nchars*9/10)
origin(m, p0);
}
void
hcheck(int m)
{
Flayer *l;
Text *t;
int reqd = 0, i;
long n, nl, a;
Rune *r;
if(m == Untagged)
return;
t = whichtext(m);
if(!t) /* possible in a half-built window */
return;
for(l = &t->l[0], i = 0; i<NL; i++, l++){
if(l->textfn==0 || !flprepare(l)) /* BUG: don't
need this if BUG below
is fixed */
continue;
a = t->l[i].origin;
n = rcontig(&t->rasp, a, a+l->f.nchars, 1);
if(n<l->f.nchars) /* text missing in middle of screen */
a += n;
else{ /* text missing at end of screen? */
Again:
if(l->f.lastlinefull)
goto Checksel; /* all's well */
a = t->l[i].origin+l->f.nchars;
n = t->rasp.nrunes-a;
if(n == 0)
goto Checksel;
if(n > TBLOCKSIZE)
n = TBLOCKSIZE;
n = rcontig(&t->rasp, a, a+n, 1);
if(n > 0){
rload(&t->rasp, a, a+n, 0);
nl = l->f.nchars;
r = scratch;
flinsert(l, r, r+n, l->origin+nl);
if(nl == l->f.nchars) /* made no progress */
goto Checksel;
goto Again;
}
}
if(!reqd){
n = rcontig(&t->rasp, a, a+TBLOCKSIZE, 0);
if(n <= 0)
panic("hcheck request==0");
outTsls(Trequest, m, a, (int)n);
outTs(Tcheck, m);
t->lock++; /* for the Trequest */
t->lock++; /* for the Tcheck */
reqd++;
}
Checksel:
flsetselect(l, l->p0, l->p1);
}
}
void
flnewlyvisible(Flayer *l)
{
hcheck(((Text *)l->user1)->tag);
}
void
hsetsnarf(int nc)
{
char *s2;
char *s1;
int i;
int n;
setcursor(mousectl, &deadmouse);
s2 = alloc(nc+1);
for(i=0; i<nc; i++)
s2[i] = getch();
s2[nc] = 0;
n = snarfswap(s2, nc, &s1);
if(n >= 0){
if(!s1)
n = 0;
s1 = realloc(s1, n+1);
if(!s1)
panic("realloc");
s1[n] = 0;
snarflen = n;
outTs(Tsetsnarf, n);
if(n>0 && write(1, s1, n)!=n)
panic("snarf write error");
free(s1);
}else
outTs(Tsetsnarf, 0);
free(s2);
setcursor(mousectl, cursor);
}
void
hplumb(int nc)
{
int i;
char *s;
Plumbmsg *m;
s = alloc(nc);
for(i = 0; i < nc; i++)
s[i] = getch();
if(plumbfd >= 0){
m = plumbunpack(s, nc);
if(m){
plumbsend(plumbfd, m);
plumbfree(m);
}
}
free(s);
}
void
hgrow(int m, long a, long new, int req)
{
int i;
Flayer *l;
Text *t = whichtext(m);
long o, b;
if(new <= 0)
panic("hgrow");
rresize(&t->rasp, a, 0L, new);
for(l = t->l, i = 0; i < NL; i++, l++){
if(!l->textfn)
continue;
o = l->origin;
b = a-o-rmissing(&t->rasp, o, a);
if(a < o)
l->origin+=new;
if(a < l->p0)
l->p0+=new;
if(a < l->p1)
l->p1+=new;
/* must prevent b temporarily becoming unsigned */
if(!req || a<o || (b > 0 && b > l->f.nchars) ||
(l->f.nchars == 0 && a-o > 0))
continue;
if(new > TBLOCKSIZE)
new = TBLOCKSIZE;
outTsls(Trequest, m, a, (int)new);
t->lock++;
req = 0;
}
}
int
hdata(int m, long a, Rune *r, int len)
{
Text *t = whichtext(m);
int i;
Flayer *l;
long o, b;
if(t->lock)
t->lock--;
if(len == 0)
return 0;
for(l = t->l, i = 0; i < NL; i++, l++){
if(!l->textfn)
continue;
o = l->origin;
b = a-o-rmissing(&t->rasp, o, a);
/* must prevent b temporarily becoming unsigned */
if(a < o || (b > 0 && b > l->f.nchars))
continue;
flinsert(l, r, r+len, o+b);
}
rdata(&t->rasp, a, a+len, r);
rclean(&t->rasp);
return len;
}
void
hcut(int m, long a, long old)
{
Flayer *l;
Text *t = whichtext(m);
int i;
long o, b;
if(t->lock)
--t->lock;
for(l = t->l, i = 0; i < NL; i++, l++){
if(l->textfn == 0)
continue;
o = l->origin;
b = a-o-rmissing(&t->rasp, o, a);
/* must prevent b temporarily becoming unsigned */
if((b<0 || b<l->f.nchars) && a+old>=o){
fldelete(l, b<0? o : o+b,
a+old-rmissing(&t->rasp, o, a+old));
}
if(a+old<o)
l->origin-=old;
else if(a<=o)
l->origin = a;
if(a+old<l->p0)
l->p0-=old;
else if(a<=l->p0)
l->p0 = a;
if(a+old<l->p1)
l->p1-=old;
else if(a<=l->p1)
l->p1 = a;
}
rresize(&t->rasp, a, old, 0L);
rclean(&t->rasp);
}