91a8d03040
fix never updating p when snarf is reallocated, resulting in memory corruption.
324 lines
5.1 KiB
C
324 lines
5.1 KiB
C
#include "vnc.h"
|
|
#include "vncv.h"
|
|
#include <cursor.h>
|
|
|
|
typedef struct Cursor Cursor;
|
|
|
|
typedef struct Mouse Mouse;
|
|
struct Mouse {
|
|
int buttons;
|
|
Point xy;
|
|
};
|
|
|
|
void
|
|
adjustwin(Vnc *v, int force)
|
|
{
|
|
int fd;
|
|
Point d;
|
|
|
|
if(force)
|
|
d = v->dim.max;
|
|
else {
|
|
/*
|
|
* limit the window to at most the vnc server's size
|
|
*/
|
|
d = subpt(screen->r.max, screen->r.min);
|
|
if(d.x > v->dim.max.x){
|
|
d.x = v->dim.max.x;
|
|
force = 1;
|
|
}
|
|
if(d.y > v->dim.max.y){
|
|
d.y = v->dim.max.y;
|
|
force = 1;
|
|
}
|
|
}
|
|
if(force) {
|
|
fd = open("/dev/wctl", OWRITE);
|
|
if(fd >= 0){
|
|
fprint(fd, "resize -dx %d -dy %d", d.x+2*Borderwidth, d.y+2*Borderwidth);
|
|
close(fd);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
resized(int first)
|
|
{
|
|
lockdisplay(display);
|
|
if(getwindow(display, Refnone) < 0)
|
|
sysfatal("internal error: can't get the window image");
|
|
if((vnc->canresize&2) == 0)
|
|
adjustwin(vnc, first);
|
|
unlockdisplay(display);
|
|
requestupdate(vnc, 0);
|
|
}
|
|
|
|
static Cursor dotcursor = {
|
|
{-7, -7},
|
|
{0x00, 0x00,
|
|
0x00, 0x00,
|
|
0x00, 0x00,
|
|
0x00, 0x00,
|
|
0x03, 0xc0,
|
|
0x07, 0xe0,
|
|
0x0f, 0xf0,
|
|
0x0f, 0xf0,
|
|
0x0f, 0xf0,
|
|
0x07, 0xe0,
|
|
0x03, 0xc0,
|
|
0x00, 0x00,
|
|
0x00, 0x00,
|
|
0x00, 0x00,
|
|
0x00, 0x00,
|
|
0x00, 0x00, },
|
|
{0x00, 0x00,
|
|
0x00, 0x00,
|
|
0x00, 0x00,
|
|
0x00, 0x00,
|
|
0x00, 0x00,
|
|
0x03, 0xc0,
|
|
0x07, 0xe0,
|
|
0x07, 0xe0,
|
|
0x07, 0xe0,
|
|
0x03, 0xc0,
|
|
0x00, 0x00,
|
|
0x00, 0x00,
|
|
0x00, 0x00,
|
|
0x00, 0x00,
|
|
0x00, 0x00,
|
|
0x00, 0x00, }
|
|
};
|
|
|
|
static void
|
|
mouseevent(Vnc *v, Mouse m)
|
|
{
|
|
vnclock(v);
|
|
vncwrchar(v, MMouse);
|
|
vncwrchar(v, m.buttons);
|
|
vncwrpoint(v, m.xy);
|
|
vncflush(v);
|
|
vncunlock(v);
|
|
}
|
|
|
|
void
|
|
mousewarp(Point pt)
|
|
{
|
|
pt = addpt(pt, screen->r.min);
|
|
if(fprint(mousefd, "m%d %d", pt.x, pt.y) < 0)
|
|
fprint(2, "mousefd write: %r\n");
|
|
}
|
|
|
|
void
|
|
initmouse(void)
|
|
{
|
|
char buf[1024];
|
|
|
|
snprint(buf, sizeof buf, "%s/mouse", display->devdir);
|
|
if((mousefd = open(buf, ORDWR)) < 0)
|
|
sysfatal("open %s: %r", buf);
|
|
}
|
|
|
|
enum {
|
|
EventSize = 1+4*12
|
|
};
|
|
void
|
|
readmouse(Vnc *v)
|
|
{
|
|
int cursorfd, len, n;
|
|
char buf[10*EventSize], *start, *end;
|
|
uchar curs[2*4+2*2*16];
|
|
Cursor *cs;
|
|
Mouse m;
|
|
|
|
cs = &dotcursor;
|
|
|
|
snprint(buf, sizeof buf, "%s/cursor", display->devdir);
|
|
if((cursorfd = open(buf, OWRITE)) < 0)
|
|
sysfatal("open %s: %r", buf);
|
|
|
|
BPLONG(curs+0*4, cs->offset.x);
|
|
BPLONG(curs+1*4, cs->offset.y);
|
|
memmove(curs+2*4, cs->clr, 2*2*16);
|
|
write(cursorfd, curs, sizeof curs);
|
|
|
|
resized(1);
|
|
start = end = buf;
|
|
len = 0;
|
|
for(;;){
|
|
if((n = read(mousefd, end, sizeof(buf) - (end - buf))) < 0)
|
|
sysfatal("read mouse failed");
|
|
|
|
len += n;
|
|
end += n;
|
|
while(len >= EventSize){
|
|
if(*start == 'm'){
|
|
m.xy.x = atoi(start+1);
|
|
m.xy.y = atoi(start+1+12);
|
|
m.buttons = atoi(start+1+2*12) & 0x1F;
|
|
m.xy = subpt(m.xy, screen->r.min);
|
|
if(ptinrect(m.xy, v->dim)){
|
|
mouseevent(v, m);
|
|
/* send wheel button *release* */
|
|
if ((m.buttons & 0x7) != m.buttons) {
|
|
m.buttons &= 0x7;
|
|
mouseevent(v, m);
|
|
}
|
|
}
|
|
} else
|
|
resized(0);
|
|
start += EventSize;
|
|
len -= EventSize;
|
|
}
|
|
if(start - buf > sizeof(buf) - EventSize){
|
|
memmove(buf, start, len);
|
|
start = buf;
|
|
end = start+len;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int
|
|
tcs(int fd0, int fd1)
|
|
{
|
|
int pfd[2];
|
|
|
|
if(strcmp(charset, "utf-8") == 0)
|
|
goto Dup;
|
|
if(pipe(pfd) < 0)
|
|
goto Dup;
|
|
switch(rfork(RFPROC|RFFDG|RFMEM)){
|
|
case -1:
|
|
close(pfd[0]);
|
|
close(pfd[1]);
|
|
goto Dup;
|
|
case 0:
|
|
if(fd0 < 0){
|
|
dup(pfd[0], 0);
|
|
dup(fd1, 1);
|
|
close(fd1);
|
|
} else {
|
|
dup(pfd[0], 1);
|
|
dup(fd0, 0);
|
|
close(fd0);
|
|
}
|
|
close(pfd[0]);
|
|
close(pfd[1]);
|
|
execl("/bin/tcs", "tcs", fd0 < 0 ? "-f" : "-t", charset, nil);
|
|
execl("/bin/cat", "cat", nil);
|
|
_exits(0);
|
|
}
|
|
close(pfd[0]);
|
|
return pfd[1];
|
|
Dup:
|
|
return dup(fd0 < 0 ? fd1 : fd0, -1);
|
|
}
|
|
|
|
static int snarffd = -1;
|
|
static ulong snarfvers;
|
|
|
|
static int
|
|
gotsnarf(void)
|
|
{
|
|
Dir *dir;
|
|
int ret;
|
|
|
|
if(snarffd < 0 || (dir = dirfstat(snarffd)) == nil)
|
|
return 0;
|
|
|
|
ret = dir->qid.vers != snarfvers;
|
|
snarfvers = dir->qid.vers;
|
|
free(dir);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
writesnarf(Vnc *v, long n)
|
|
{
|
|
uchar buf[8192];
|
|
int fd, sfd;
|
|
long m;
|
|
|
|
vnclock(v);
|
|
fd = -1;
|
|
if((sfd = create("/dev/snarf", OWRITE, 0666)) >= 0){
|
|
fd = tcs(-1, sfd);
|
|
close(sfd);
|
|
}
|
|
if(fd < 0)
|
|
vncgobble(v, n);
|
|
else {
|
|
while(n > 0){
|
|
m = n;
|
|
if(m > sizeof(buf))
|
|
m = sizeof(buf);
|
|
vncrdbytes(v, buf, m);
|
|
n -= m;
|
|
write(fd, buf, m);
|
|
}
|
|
close(fd);
|
|
waitpid();
|
|
}
|
|
gotsnarf();
|
|
vncunlock(v);
|
|
}
|
|
|
|
char *
|
|
getsnarf(int *sz)
|
|
{
|
|
char *snarf, *p;
|
|
int fd, n, c;
|
|
|
|
*sz =0;
|
|
n = 8192;
|
|
p = snarf = malloc(n);
|
|
|
|
seek(snarffd, 0, 0);
|
|
if((fd = tcs(snarffd, -1)) >= 0){
|
|
while((c = read(fd, p, n)) > 0){
|
|
p += c;
|
|
n -= c;
|
|
*sz += c;
|
|
if (n == 0){
|
|
snarf = realloc(snarf, *sz + 8192);
|
|
p = snarf + *sz;
|
|
n = 8192;
|
|
}
|
|
}
|
|
close(fd);
|
|
waitpid();
|
|
}
|
|
return snarf;
|
|
}
|
|
|
|
void
|
|
checksnarf(Vnc *v)
|
|
{
|
|
char *snarf;
|
|
int len;
|
|
|
|
if(snarffd < 0){
|
|
snarffd = open("/dev/snarf", OREAD);
|
|
if(snarffd < 0)
|
|
sysfatal("can't open /dev/snarf: %r");
|
|
}
|
|
|
|
for(;;){
|
|
sleep(1000);
|
|
|
|
vnclock(v);
|
|
if(gotsnarf()){
|
|
snarf = getsnarf(&len);
|
|
|
|
vncwrchar(v, MCCut);
|
|
vncwrbytes(v, "pad", 3);
|
|
vncwrlong(v, len);
|
|
vncwrbytes(v, snarf, len);
|
|
vncflush(v);
|
|
|
|
free(snarf);
|
|
}
|
|
vncunlock(v);
|
|
}
|
|
}
|