xref: /plan9/sys/src/cmd/unix/drawterm/kern/devmouse.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1 #include	"u.h"
2 #include	"lib.h"
3 #include	"dat.h"
4 #include	"fns.h"
5 #include	"error.h"
6 
7 #include	"draw.h"
8 #include	"memdraw.h"
9 #include	"screen.h"
10 
11 int	mousequeue = 1;
12 
13 Mouseinfo	mouse;
14 Cursorinfo	cursor;
15 
16 static int	mousechanged(void*);
17 
18 enum{
19 	Qdir,
20 	Qcursor,
21 	Qmouse
22 };
23 
24 Dirtab mousedir[]={
25 	".",		{Qdir, 0, QTDIR},	0,	DMDIR|0555,
26 	"cursor",	{Qcursor},	0,			0666,
27 	"mouse",	{Qmouse},	0,			0666,
28 };
29 
30 #define	NMOUSE	(sizeof(mousedir)/sizeof(Dirtab))
31 
32 static Chan*
mouseattach(char * spec)33 mouseattach(char *spec)
34 {
35 	return devattach('m', spec);
36 }
37 
38 static Walkqid*
mousewalk(Chan * c,Chan * nc,char ** name,int nname)39 mousewalk(Chan *c, Chan *nc, char **name, int nname)
40 {
41 	return devwalk(c, nc, name, nname, mousedir, NMOUSE, devgen);
42 }
43 
44 static int
mousestat(Chan * c,uchar * db,int n)45 mousestat(Chan *c, uchar *db, int n)
46 {
47 	return devstat(c, db, n, mousedir, NMOUSE, devgen);
48 }
49 
50 static Chan*
mouseopen(Chan * c,int omode)51 mouseopen(Chan *c, int omode)
52 {
53 	switch((long)c->qid.path){
54 	case Qdir:
55 		if(omode != OREAD)
56 			error(Eperm);
57 		break;
58 	case Qmouse:
59 		lock(&mouse.lk);
60 		if(mouse.open){
61 			unlock(&mouse.lk);
62 			error(Einuse);
63 		}
64 		mouse.open = 1;
65 		unlock(&mouse.lk);
66 		break;
67 	}
68 	c->mode = openmode(omode);
69 	c->flag |= COPEN;
70 	c->offset = 0;
71 	return c;
72 }
73 
74 void
mouseclose(Chan * c)75 mouseclose(Chan *c)
76 {
77 	if(!(c->flag&COPEN))
78 		return;
79 
80 	switch((long)c->qid.path) {
81 	case Qmouse:
82 		lock(&mouse.lk);
83 		mouse.open = 0;
84 		unlock(&mouse.lk);
85 		cursorarrow();
86 	}
87 }
88 
89 
90 long
mouseread(Chan * c,void * va,long n,vlong offset)91 mouseread(Chan *c, void *va, long n, vlong offset)
92 {
93 	char buf[4*12+1];
94 	uchar *p;
95 	int i, nn;
96 	ulong msec;
97 /*	static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 };	*/
98 
99 	p = va;
100 	switch((long)c->qid.path){
101 	case Qdir:
102 		return devdirread(c, va, n, mousedir, NMOUSE, devgen);
103 
104 	case Qcursor:
105 		if(offset != 0)
106 			return 0;
107 		if(n < 2*4+2*2*16)
108 			error(Eshort);
109 		n = 2*4+2*2*16;
110 		lock(&cursor.lk);
111 		BPLONG(p+0, cursor.offset.x);
112 		BPLONG(p+4, cursor.offset.y);
113 		memmove(p+8, cursor.clr, 2*16);
114 		memmove(p+40, cursor.set, 2*16);
115 		unlock(&cursor.lk);
116 		return n;
117 
118 	case Qmouse:
119 		while(mousechanged(0) == 0)
120 			sleep(&mouse.r, mousechanged, 0);
121 
122 		lock(&screen.lk);
123 		if(screen.reshaped) {
124 			screen.reshaped = 0;
125 			sprint(buf, "t%11d %11d", 0, ticks());
126 			if(n > 1+2*12)
127 				n = 1+2*12;
128 			memmove(va, buf, n);
129 			unlock(&screen.lk);
130 			return n;
131 		}
132 		unlock(&screen.lk);
133 
134 		lock(&mouse.lk);
135 		i = mouse.ri;
136 		nn = (mouse.wi + Mousequeue - i) % Mousequeue;
137 		if(nn < 1)
138 			panic("empty mouse queue");
139 		msec = ticks();
140 		while(nn > 1) {
141 			if(mouse.queue[i].msec + Mousewindow > msec)
142 				break;
143 			i = (i+1)%Mousequeue;
144 			nn--;
145 		}
146 		sprint(buf, "m%11d %11d %11d %11d",
147 			mouse.queue[i].xy.x,
148 			mouse.queue[i].xy.y,
149 			mouse.queue[i].buttons,
150 			mouse.queue[i].msec);
151 		mouse.ri = (i+1)%Mousequeue;
152 		unlock(&mouse.lk);
153 		if(n > 1+4*12)
154 			n = 1+4*12;
155 		memmove(va, buf, n);
156 		return n;
157 	}
158 	return 0;
159 }
160 
161 long
mousewrite(Chan * c,void * va,long n,vlong offset)162 mousewrite(Chan *c, void *va, long n, vlong offset)
163 {
164 	char *p;
165 	Point pt;
166 	char buf[64];
167 
168 	USED(offset);
169 
170 	p = va;
171 	switch((long)c->qid.path){
172 	case Qdir:
173 		error(Eisdir);
174 
175 	case Qcursor:
176 		if(n < 2*4+2*2*16){
177 			cursorarrow();
178 		}else{
179 			n = 2*4+2*2*16;
180 			lock(&cursor.lk);
181 			cursor.offset.x = BGLONG(p+0);
182 			cursor.offset.y = BGLONG(p+4);
183 			memmove(cursor.clr, p+8, 2*16);
184 			memmove(cursor.set, p+40, 2*16);
185 			unlock(&cursor.lk);
186 			setcursor();
187 		}
188 		return n;
189 
190 	case Qmouse:
191 		if(n > sizeof buf-1)
192 			n = sizeof buf -1;
193 		memmove(buf, va, n);
194 		buf[n] = 0;
195 		p = 0;
196 		pt.x = strtoul(buf+1, &p, 0);
197 		if(p == 0)
198 			error(Eshort);
199 		pt.y = strtoul(p, 0, 0);
200 		if(ptinrect(pt, gscreen->r))
201 			mouseset(pt);
202 		return n;
203 	}
204 
205 	error(Egreg);
206 	return -1;
207 }
208 
209 int
mousechanged(void * a)210 mousechanged(void *a)
211 {
212 	USED(a);
213 
214 	return mouse.ri != mouse.wi || screen.reshaped;
215 }
216 
217 Dev mousedevtab = {
218 	'm',
219 	"mouse",
220 
221 	devreset,
222 	devinit,
223 	devshutdown,
224 	mouseattach,
225 	mousewalk,
226 	mousestat,
227 	mouseopen,
228 	devcreate,
229 	mouseclose,
230 	mouseread,
231 	devbread,
232 	mousewrite,
233 	devbwrite,
234 	devremove,
235 	devwstat,
236 };
237 
238