]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vnc/devmouse.c
merge
[plan9front.git] / sys / src / cmd / vnc / devmouse.c
1 #include        <u.h>
2 #include        <libc.h>
3 #include        "compat.h"
4 #include        "error.h"
5
6 #define Image   IMAGE
7 #include        <draw.h>
8 #include        <memdraw.h>
9 #include        <cursor.h>
10 #include        "screen.h"
11
12 typedef struct Mouseinfo        Mouseinfo;
13 typedef struct Mousestate       Mousestate;
14
15 struct Mousestate
16 {
17         Point   xy;             /* mouse.xy */
18         int     buttons;        /* mouse.buttons */
19         ulong   counter;        /* increments every update */
20         ulong   msec;           /* time of last event */
21 };
22
23 struct Mouseinfo
24 {
25         Lock;
26         Mousestate;
27         ulong   lastcounter;    /* value when /dev/mouse read */
28         Rendez  r;
29         Ref;
30         int     open;
31         Mousestate      queue[16];      /* circular buffer of click events */
32         ulong   ri;             /* read index into queue */
33         ulong   wi;             /* write index into queue */
34 };
35
36 Mouseinfo       mouse;
37 Cursorinfo      cursor;
38 Cursor          curs;
39
40 void    Cursortocursor(Cursor*);
41 int     mousechanged(void*);
42
43 enum{
44         Qdir,
45         Qcursor,
46         Qmouse,
47         Qmousein,
48         Qmousectl,
49 };
50
51 static Dirtab mousedir[]={
52         ".",    {Qdir, 0, QTDIR},       0,                      DMDIR|0555,
53         "cursor",       {Qcursor},      0,                      0666,
54         "mouse",        {Qmouse},       0,                      0666,
55         "mousein",      {Qmousein},     0,                      0222,
56         "mousectl",     {Qmousectl},    0,                      0222,
57 };
58
59 Cursor  arrow = {
60         { -1, -1 },
61         { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
62           0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
63           0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
64           0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
65         },
66         { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
67           0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
68           0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
69           0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
70         },
71 };
72
73 extern Memimage* gscreen;
74 extern void mousewarpnote(Point);
75
76 static void
77 mousereset(void)
78 {
79         curs = arrow;
80         Cursortocursor(&arrow);
81 }
82
83 static void
84 mouseinit(void)
85 {
86         curs = arrow;
87         Cursortocursor(&arrow);
88         cursoron();
89 }
90
91 static Chan*
92 mouseattach(char *spec)
93 {
94         return devattach('m', spec);
95 }
96
97 static Walkqid*
98 mousewalk(Chan *c, Chan *nc, char **name, int nname)
99 {
100         return devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);
101 }
102
103 static int
104 mousestat(Chan *c, uchar *db, int n)
105 {
106         return devstat(c, db, n, mousedir, nelem(mousedir), devgen);
107 }
108
109 static Chan*
110 mouseopen(Chan *c, int omode)
111 {
112         int mode;
113
114         mode = openmode(omode);
115         switch((ulong)c->qid.path){
116         case Qdir:
117                 if(omode != OREAD)
118                         error(Eperm);
119                 break;
120         case Qmousein:
121         case Qmousectl:
122                 error(Egreg);
123                 break;
124         case Qmouse:
125                 if(_tas(&mouse.open) != 0)
126                         error(Einuse);
127                 mouse.lastcounter = mouse.counter;
128                 /* wet floor */
129         case Qcursor:
130                 incref(&mouse);
131         }
132         c->mode = mode;
133         c->flag |= COPEN;
134         c->offset = 0;
135         return c;
136 }
137
138 static void
139 mouseclose(Chan *c)
140 {
141         if((c->qid.type&QTDIR)!=0 || (c->flag&COPEN)==0)
142                 return;
143         switch((ulong)c->qid.path){
144         case Qmouse:
145                 mouse.open = 0;
146                 /* wet floor */
147         case Qcursor:
148                 if(decref(&mouse) != 0)
149                         return;
150                 cursoroff();
151                 curs = arrow;
152                 Cursortocursor(&arrow);
153                 cursoron();
154         }
155 }
156
157
158 static long
159 mouseread(Chan *c, void *va, long n, vlong off)
160 {
161         char buf[1+4*12+1];
162         uchar *p;
163         ulong offset = off;
164         Mousestate m;
165
166         p = va;
167         switch((ulong)c->qid.path){
168         case Qdir:
169                 return devdirread(c, va, n, mousedir, nelem(mousedir), devgen);
170
171         case Qcursor:
172                 if(offset != 0)
173                         return 0;
174                 if(n < 2*4+2*2*16)
175                         error(Eshort);
176                 n = 2*4+2*2*16;
177                 BPLONG(p+0, curs.offset.x);
178                 BPLONG(p+4, curs.offset.y);
179                 memmove(p+8, curs.clr, 2*16);
180                 memmove(p+40, curs.set, 2*16);
181                 return n;
182
183         case Qmouse:
184                 while(mousechanged(0) == 0)
185                         rendsleep(&mouse.r, mousechanged, 0);
186
187                 lock(&mouse);
188                 if(mouse.ri != mouse.wi)
189                         m = mouse.queue[mouse.ri++ % nelem(mouse.queue)];
190                 else
191                         m = mouse.Mousestate;
192                 unlock(&mouse);
193
194                 sprint(buf, "m%11d %11d %11d %11lud ",
195                         m.xy.x, m.xy.y, m.buttons, m.msec);
196
197                 mouse.lastcounter = m.counter;
198
199                 if(n > 1+4*12)
200                         n = 1+4*12;
201                 memmove(va, buf, n);
202                 return n;
203         }
204         return 0;
205 }
206
207 static long
208 mousewrite(Chan *c, void *va, long n, vlong)
209 {
210         char *p;
211         Point pt;
212         char buf[64];
213
214         p = va;
215         switch((ulong)c->qid.path){
216         case Qdir:
217                 error(Eisdir);
218
219         case Qcursor:
220                 cursoroff();
221                 if(n < 2*4+2*2*16){
222                         curs = arrow;
223                         Cursortocursor(&arrow);
224                 }else{
225                         n = 2*4+2*2*16;
226                         curs.offset.x = BGLONG(p+0);
227                         curs.offset.y = BGLONG(p+4);
228                         memmove(curs.clr, p+8, 2*16);
229                         memmove(curs.set, p+40, 2*16);
230                         Cursortocursor(&curs);
231                 }
232                 cursoron();
233                 return n;
234
235         case Qmouse:
236                 if(n > sizeof buf-1)
237                         n = sizeof buf -1;
238                 memmove(buf, va, n);
239                 buf[n] = 0;
240
241                 pt.x = strtol(buf+1, &p, 0);
242                 if(*p == 0)
243                         error(Eshort);
244                 pt.y = strtol(p, 0, 0);
245                 absmousetrack(pt.x, pt.y, mouse.buttons, nsec()/(1000*1000LL));
246                 mousewarpnote(pt);
247                 return n;
248         }
249
250         error(Egreg);
251         return -1;
252 }
253
254 Dev mousedevtab = {
255         'm',
256         "mouse",
257
258         mousereset,
259         mouseinit,
260         mouseattach,
261         mousewalk,
262         mousestat,
263         mouseopen,
264         devcreate,
265         mouseclose,
266         mouseread,
267         devbread,
268         mousewrite,
269         devbwrite,
270         devremove,
271         devwstat,
272 };
273
274 void
275 Cursortocursor(Cursor *c)
276 {
277         lock(&cursor);
278         memmove(&cursor.Cursor, c, sizeof(Cursor));
279         setcursor(c);
280         unlock(&cursor);
281 }
282
283 void
284 absmousetrack(int x, int y, int b, ulong msec)
285 {
286         int lastb;
287
288         if(gscreen==nil)
289                 return;
290
291         if(x < gscreen->clipr.min.x)
292                 x = gscreen->clipr.min.x;
293         if(x >= gscreen->clipr.max.x)
294                 x = gscreen->clipr.max.x-1;
295         if(y < gscreen->clipr.min.y)
296                 y = gscreen->clipr.min.y;
297         if(y >= gscreen->clipr.max.y)
298                 y = gscreen->clipr.max.y-1;
299
300
301         lock(&mouse);
302         mouse.xy = Pt(x, y);
303         lastb = mouse.buttons;
304         mouse.buttons = b;
305         mouse.msec = msec;
306         mouse.counter++;
307
308         /*
309          * if the queue fills, don't queue any more events until a
310          * reader polls the mouse.
311          */
312         if(b != lastb && (mouse.wi-mouse.ri) < nelem(mouse.queue))
313                 mouse.queue[mouse.wi++ % nelem(mouse.queue)] = mouse.Mousestate;
314         unlock(&mouse);
315
316         rendwakeup(&mouse.r);
317
318         cursoron();
319 }
320
321 int
322 mousechanged(void*)
323 {
324         return mouse.lastcounter != mouse.counter;
325 }
326
327 Point
328 mousexy(void)
329 {
330         return mouse.xy;
331 }