xref: /inferno-os/emu/port/devpointer.c (revision 75762b265ad6efb5f353e0c21737a105b21a74a3)
1 /*
2  * mouse or stylus
3  */
4 
5 #include	"dat.h"
6 #include	"fns.h"
7 #include	"../port/error.h"
8 
9 #include <draw.h>
10 #include <memdraw.h>
11 #include <cursor.h>
12 
13 #define	cursorenable()
14 #define	cursordisable()
15 
16 enum{
17 	Qdir,
18 	Qpointer,
19 	Qcursor
20 };
21 
22 typedef struct Pointer Pointer;
23 
24 struct Pointer {
25 	int	x;
26 	int	y;
27 	int	b;
28 	ulong	msec;
29 };
30 
31 static struct
32 {
33 	Pointer	v;
34 	int	modify;
35 	int	lastb;
36 	Rendez	r;
37 	Ref	ref;
38 	QLock	q;
39 } mouse;
40 
41 static
42 Dirtab pointertab[]={
43 	".",			{Qdir, 0, QTDIR},	0,	0555,
44 	"pointer",		{Qpointer},	0,	0666,
45 	"cursor",		{Qcursor},		0,	0222,
46 };
47 
48 enum {
49 	Nevent = 16	/* enough for some */
50 };
51 
52 static struct {
53 	int	rd;
54 	int	wr;
55 	Pointer	clicks[Nevent];
56 	Rendez r;
57 	int	full;
58 	int	put;
59 	int	get;
60 } ptrq;
61 
62 /*
63  * called by any source of pointer data
64  */
65 void
66 mousetrack(int b, int x, int y, int isdelta)
67 {
68 	int lastb;
69 	ulong msec;
70 	Pointer e;
71 
72 	if(isdelta){
73 		x += mouse.v.x;
74 		y += mouse.v.y;
75 	}
76 	msec = osmillisec();
77 	lastb = mouse.v.b;
78 	mouse.v.x = x;
79 	mouse.v.y = y;
80 	mouse.v.b = b;
81 	mouse.v.msec = msec;
82 	if(!ptrq.full && lastb != b){
83 		e = mouse.v;
84 		ptrq.clicks[ptrq.wr] = e;
85 		if(++ptrq.wr >= Nevent)
86 			ptrq.wr = 0;
87 		if(ptrq.wr == ptrq.rd)
88 			ptrq.full = 1;
89 	}
90 	mouse.modify = 1;
91 	ptrq.put++;
92 	Wakeup(&ptrq.r);
93 /*	drawactive(1);	*/
94 /*	setpointer(x, y); */
95 }
96 
97 static int
98 ptrqnotempty(void *x)
99 {
100 	USED(x);
101 	return ptrq.full || ptrq.put != ptrq.get;
102 }
103 
104 static Pointer
105 mouseconsume(void)
106 {
107 	Pointer e;
108 
109 	Sleep(&ptrq.r, ptrqnotempty, 0);
110 	ptrq.full = 0;
111 	ptrq.get = ptrq.put;
112 	if(ptrq.rd != ptrq.wr){
113 		e = ptrq.clicks[ptrq.rd];
114 		if(++ptrq.rd >= Nevent)
115 			ptrq.rd = 0;
116 	}else
117 		e = mouse.v;
118 	return e;
119 }
120 
121 Point
122 mousexy(void)
123 {
124 	return Pt(mouse.v.x, mouse.v.y);
125 }
126 
127 
128 static Chan*
129 pointerattach(char* spec)
130 {
131 	return devattach('m', spec);
132 }
133 
134 static Walkqid*
135 pointerwalk(Chan *c, Chan *nc, char **name, int nname)
136 {
137 	Walkqid *wq;
138 
139 	wq = devwalk(c, nc, name, nname, pointertab, nelem(pointertab), devgen);
140 	if(wq != nil && wq->clone != c && wq->clone != nil && (ulong)c->qid.path == Qpointer)
141 		incref(&mouse.ref);	/* can this happen? */
142 	return wq;
143 }
144 
145 static int
146 pointerstat(Chan* c, uchar *db, int n)
147 {
148 	return devstat(c, db, n, pointertab, nelem(pointertab), devgen);
149 }
150 
151 static Chan*
152 pointeropen(Chan* c, int omode)
153 {
154 	c = devopen(c, omode, pointertab, nelem(pointertab), devgen);
155 	if((ulong)c->qid.path == Qpointer){
156 		if(waserror()){
157 			c->flag &= ~COPEN;
158 			nexterror();
159 		}
160 		if(!canqlock(&mouse.q))
161 			error(Einuse);
162 		if(incref(&mouse.ref) != 1){
163 			qunlock(&mouse.q);
164 			error(Einuse);
165 		}
166 		cursorenable();
167 		qunlock(&mouse.q);
168 		poperror();
169 	}
170 	return c;
171 }
172 
173 static void
174 pointerclose(Chan* c)
175 {
176 	if((c->flag & COPEN) == 0)
177 		return;
178 	switch((ulong)c->qid.path){
179 	case Qpointer:
180 		qlock(&mouse.q);
181 		if(decref(&mouse.ref) == 0){
182 			cursordisable();
183 		}
184 		qunlock(&mouse.q);
185 		break;
186 	}
187 }
188 
189 static long
190 pointerread(Chan* c, void* a, long n, vlong off)
191 {
192 	Pointer mt;
193 	char buf[1+4*12+1];
194 	int l;
195 
196 	USED(&off);
197 	switch((ulong)c->qid.path){
198 	case Qdir:
199 		return devdirread(c, a, n, pointertab, nelem(pointertab), devgen);
200 	case Qpointer:
201 		qlock(&mouse.q);
202 		if(waserror()) {
203 			qunlock(&mouse.q);
204 			nexterror();
205 		}
206 		mt = mouseconsume();
207 		poperror();
208 		qunlock(&mouse.q);
209 		l = snprint(buf, sizeof(buf), "m%11d %11d %11d %11lud ", mt.x, mt.y, mt.b, mt.msec);
210 		if(l < n)
211 			n = l;
212 		memmove(a, buf, n);
213 		break;
214 	default:
215 		n=0;
216 		break;
217 	}
218 	return n;
219 }
220 
221 static long
222 pointerwrite(Chan* c, void* va, long n, vlong off)
223 {
224 	char *a = va;
225 	char buf[128];
226 	int b, x, y;
227 	Drawcursor cur;
228 
229 	USED(&off);
230 	switch((ulong)c->qid.path){
231 	case Qpointer:
232 		if(n > sizeof buf-1)
233 			n = sizeof buf -1;
234 		memmove(buf, va, n);
235 		buf[n] = 0;
236 		x = strtoul(buf+1, &a, 0);
237 		if(*a == 0)
238 			error(Eshort);
239 		y = strtoul(a, &a, 0);
240 		if(*a != 0)
241 			b = strtoul(a, 0, 0);
242 		else
243 			b = mouse.v.b;
244 		/*mousetrack(b, x, y, msec);*/
245 		setpointer(x, y);
246 		USED(b);
247 		break;
248 	case Qcursor:
249 		/* TO DO: perhaps interpret data as an Image */
250 		/*
251 		 *  hotx[4] hoty[4] dx[4] dy[4] clr[dx/8 * dy/2] set[dx/8 * dy/2]
252 		 *  dx must be a multiple of 8; dy must be a multiple of 2.
253 		 */
254 		if(n == 0){
255 			cur.data = nil;
256 			drawcursor(&cur);
257 			break;
258 		}
259 		if(n < 8)
260 			error(Eshort);
261 		cur.hotx = BGLONG((uchar*)va+0*4);
262 		cur.hoty = BGLONG((uchar*)va+1*4);
263 		cur.minx = 0;
264 		cur.miny = 0;
265 		cur.maxx = BGLONG((uchar*)va+2*4);
266 		cur.maxy = BGLONG((uchar*)va+3*4);
267 		if(cur.maxx%8 != 0 || cur.maxy%2 != 0 || n-4*4 != (cur.maxx/8 * cur.maxy))
268 			error(Ebadarg);
269 		cur.data = (uchar*)va + 4*4;
270 		drawcursor(&cur);
271 		break;
272 	default:
273 		error(Ebadusefd);
274 	}
275 	return n;
276 }
277 
278 Dev pointerdevtab = {
279 	'm',
280 	"pointer",
281 
282 	devinit,
283 	pointerattach,
284 	pointerwalk,
285 	pointerstat,
286 	pointeropen,
287 	devcreate,
288 	pointerclose,
289 	pointerread,
290 	devbread,
291 	pointerwrite,
292 	devbwrite,
293 	devremove,
294 	devwstat,
295 };
296