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