xref: /plan9/sys/src/cmd/vnc/wsys.c (revision cd42b31485b3c902f838a8604fadd3402f9f1270)
1 #include "vnc.h"
2 #include "vncv.h"
3 #include <cursor.h>
4 
5 typedef struct Cursor Cursor;
6 
7 typedef struct Mouse Mouse;
8 struct Mouse {
9 	int buttons;
10 	Point xy;
11 };
12 
13 static void
resize(Vnc * v,int first)14 resize(Vnc *v, int first)
15 {
16 	int fd;
17 	Point d;
18 
19 	d = addpt(v->dim, Pt(2*Borderwidth, 2*Borderwidth));
20 	lockdisplay(display);
21 
22 	if(getwindow(display, Refnone) < 0)
23 		sysfatal("internal error: can't get the window image");
24 
25 	/*
26 	 * limit the window to at most the vnc server's size
27 	 */
28 	if(first || d.x < Dx(screen->r) || d.y < Dy(screen->r)){
29 		fd = open("/dev/wctl", OWRITE);
30 		if(fd >= 0){
31 			fprint(fd, "resize -dx %d -dy %d", d.x, d.y);
32 			close(fd);
33 		}
34 	}
35 	unlockdisplay(display);
36 }
37 
38 static void
eresized(void)39 eresized(void)
40 {
41 	resize(vnc, 0);
42 
43 	requestupdate(vnc, 0);
44 }
45 
46 static Cursor dotcursor = {
47 	{-7, -7},
48 	{0x00, 0x00,
49 	 0x00, 0x00,
50 	 0x00, 0x00,
51 	 0x00, 0x00,
52 	 0x03, 0xc0,
53 	 0x07, 0xe0,
54 	 0x0f, 0xf0,
55 	 0x0f, 0xf0,
56 	 0x0f, 0xf0,
57 	 0x07, 0xe0,
58 	 0x03, 0xc0,
59 	 0x00, 0x00,
60 	 0x00, 0x00,
61 	 0x00, 0x00,
62 	 0x00, 0x00,
63 	 0x00, 0x00, },
64 	{0x00, 0x00,
65 	 0x00, 0x00,
66 	 0x00, 0x00,
67 	 0x00, 0x00,
68 	 0x00, 0x00,
69 	 0x03, 0xc0,
70 	 0x07, 0xe0,
71 	 0x07, 0xe0,
72 	 0x07, 0xe0,
73 	 0x03, 0xc0,
74 	 0x00, 0x00,
75 	 0x00, 0x00,
76 	 0x00, 0x00,
77 	 0x00, 0x00,
78 	 0x00, 0x00,
79 	 0x00, 0x00, }
80 };
81 
82 static void
mouseevent(Vnc * v,Mouse m)83 mouseevent(Vnc *v, Mouse m)
84 {
85 	vnclock(v);
86 	vncwrchar(v, MMouse);
87 	vncwrchar(v, m.buttons);
88 	vncwrpoint(v, m.xy);
89 	vncflush(v);
90 	vncunlock(v);
91 }
92 
93 void
mousewarp(Point pt)94 mousewarp(Point pt)
95 {
96 	pt = addpt(pt, screen->r.min);
97 	if(fprint(mousefd, "m%d %d", pt.x, pt.y) < 0)
98 		fprint(2, "mousefd write: %r\n");
99 }
100 
101 void
initmouse(void)102 initmouse(void)
103 {
104 	char buf[1024];
105 
106 	snprint(buf, sizeof buf, "%s/mouse", display->devdir);
107 	if((mousefd = open(buf, ORDWR)) < 0)
108 		sysfatal("open %s: %r", buf);
109 }
110 
111 enum {
112 	EventSize = 1+4*12
113 };
114 void
readmouse(Vnc * v)115 readmouse(Vnc *v)
116 {
117 	int cursorfd, len, n;
118 	char buf[10*EventSize], *start, *end;
119 	uchar curs[2*4+2*2*16];
120 	Cursor *cs;
121 	Mouse m;
122 
123 	cs = &dotcursor;
124 
125 	snprint(buf, sizeof buf, "%s/cursor", display->devdir);
126 	if((cursorfd = open(buf, OWRITE)) < 0)
127 		sysfatal("open %s: %r", buf);
128 
129 	BPLONG(curs+0*4, cs->offset.x);
130 	BPLONG(curs+1*4, cs->offset.y);
131 	memmove(curs+2*4, cs->clr, 2*2*16);
132 	write(cursorfd, curs, sizeof curs);
133 
134 	resize(v, 1);
135 	requestupdate(vnc, 0);
136 	start = end = buf;
137 	len = 0;
138 	for(;;){
139 		if((n = read(mousefd, end, sizeof(buf) - (end - buf))) < 0)
140 			sysfatal("read mouse failed");
141 
142 		len += n;
143 		end += n;
144 		while(len >= EventSize){
145 			if(*start == 'm'){
146 				m.xy.x = atoi(start+1);
147 				m.xy.y = atoi(start+1+12);
148 				m.buttons = atoi(start+1+2*12) & 0x1F;
149 				m.xy = subpt(m.xy, screen->r.min);
150 				if(ptinrect(m.xy, Rpt(ZP, v->dim))){
151 					mouseevent(v, m);
152 					/* send wheel button *release* */
153 					if ((m.buttons & 0x7) != m.buttons) {
154 						m.buttons &= 0x7;
155 						mouseevent(v, m);
156 					}
157 				}
158 			} else
159 				eresized();
160 
161 			start += EventSize;
162 			len -= EventSize;
163 		}
164 		if(start - buf > sizeof(buf) - EventSize){
165 			memmove(buf, start, len);
166 			start = buf;
167 			end = start+len;
168 		}
169 	}
170 }
171 
172 static int snarffd = -1;
173 static ulong snarfvers;
174 
175 void
writesnarf(Vnc * v,long n)176 writesnarf(Vnc *v, long n)
177 {
178 	uchar buf[8192];
179 	long m;
180 	Biobuf *b;
181 
182 	if((b = Bopen("/dev/snarf", OWRITE)) == nil){
183 		vncgobble(v, n);
184 		return;
185 	}
186 
187 	while(n > 0){
188 		m = n;
189 		if(m > sizeof(buf))
190 			m = sizeof(buf);
191 		vncrdbytes(v, buf, m);
192 		n -= m;
193 
194 		Bwrite(b, buf, m);
195 	}
196 	Bterm(b);
197 	snarfvers++;
198 }
199 
200 char *
getsnarf(int * sz)201 getsnarf(int *sz)
202 {
203 	char *snarf, *p;
204 	int n, c;
205 
206 	*sz =0;
207 	n = 8192;
208 	p = snarf = malloc(n);
209 
210 	seek(snarffd, 0, 0);
211 	while ((c = read(snarffd, p, n)) > 0){
212 		p += c;
213 		n -= c;
214 		*sz += c;
215 		if (n == 0){
216 			snarf = realloc(snarf, *sz + 8192);
217 			n = 8192;
218 		}
219 	}
220 	return snarf;
221 }
222 
223 void
checksnarf(Vnc * v)224 checksnarf(Vnc *v)
225 {
226 	Dir *dir;
227 	char *snarf;
228 	int len;
229 
230 	if(snarffd < 0){
231 		snarffd = open("/dev/snarf", OREAD);
232 		if(snarffd < 0)
233 			sysfatal("can't open /dev/snarf: %r");
234 	}
235 
236 	for(;;){
237 		sleep(1000);
238 
239 		dir = dirstat("/dev/snarf");
240 		if(dir == nil)	/* this happens under old drawterm */
241 			continue;
242 		if(dir->qid.vers > snarfvers){
243 			snarf = getsnarf(&len);
244 
245 			vnclock(v);
246 			vncwrchar(v, MCCut);
247 			vncwrbytes(v, "pad", 3);
248 			vncwrlong(v, len);
249 			vncwrbytes(v, snarf, len);
250 			vncflush(v);
251 			vncunlock(v);
252 
253 			free(snarf);
254 
255 			snarfvers = dir->qid.vers;
256 		}
257 		free(dir);
258 	}
259 }
260