]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vnc/devmouse.c
vnc: don't prompt for password on auth_respond() failure
[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         Mousestate;
26         int     dx;
27         int     dy;
28         int     track;          /* dx & dy updated */
29         int     redraw;         /* update cursor on screen */
30         ulong   lastcounter;    /* value when /dev/mouse read */
31         Rendez  r;
32         Ref;
33         QLock;
34         int     open;
35         int     acceleration;
36         int     maxacc;
37         Mousestate      queue[16];      /* circular buffer of click events */
38         int     ri;     /* read index into queue */
39         int     wi;     /* write index into queue */
40         uchar   qfull;  /* queue is full */
41 };
42
43 Mouseinfo       mouse;
44 Cursorinfo      cursor;
45 int             mouseshifted;
46 Cursor          curs;
47
48 void    Cursortocursor(Cursor*);
49 int     mousechanged(void*);
50 static void mouseclock(void);
51
52 enum{
53         Qdir,
54         Qcursor,
55         Qmouse,
56         Qmousein,
57         Qmousectl,
58 };
59
60 static Dirtab mousedir[]={
61         ".",    {Qdir, 0, QTDIR},       0,                      DMDIR|0555,
62         "cursor",       {Qcursor},      0,                      0666,
63         "mouse",        {Qmouse},       0,                      0666,
64         "mousein",      {Qmousein},     0,                      0222,
65         "mousectl",     {Qmousectl},    0,                      0222,
66 };
67
68 static uchar buttonmap[8] = {
69         0, 1, 2, 3, 4, 5, 6, 7,
70 };
71 static int mouseswap;
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         cursoron(1);
87 }
88
89 static Chan*
90 mouseattach(char *spec)
91 {
92         return devattach('m', spec);
93 }
94
95 static Walkqid*
96 mousewalk(Chan *c, Chan *nc, char **name, int nname)
97 {
98         Walkqid *wq;
99
100         wq = devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);
101         if(wq != nil && wq->clone != c && (wq->clone->qid.type&QTDIR)==0)
102                 incref(&mouse);
103         return wq;
104 }
105
106 static int
107 mousestat(Chan *c, uchar *db, int n)
108 {
109         return devstat(c, db, n, mousedir, nelem(mousedir), devgen);
110 }
111
112 static Chan*
113 mouseopen(Chan *c, int omode)
114 {
115         switch((ulong)c->qid.path){
116         case Qdir:
117                 if(omode != OREAD)
118                         error(Eperm);
119                 break;
120         case Qmouse:
121                 lock(&mouse);
122                 if(mouse.open){
123                         unlock(&mouse);
124                         error(Einuse);
125                 }
126                 mouse.open = 1;
127                 mouse.ref++;
128                 unlock(&mouse);
129                 break;
130         case Qmousein:
131         case Qmousectl:
132                 error(Egreg);   /* dummy */
133                 break;
134         default:
135                 incref(&mouse);
136         }
137         c->mode = openmode(omode);
138         c->flag |= COPEN;
139         c->offset = 0;
140         return c;
141 }
142
143 static void
144 mousecreate(Chan*, char*, int, ulong)
145 {
146         error(Eperm);
147 }
148
149 static void
150 mouseclose(Chan *c)
151 {
152         if((c->qid.type&QTDIR)==0 && (c->flag&COPEN)){
153                 lock(&mouse);
154                 if(c->qid.path == Qmouse)
155                         mouse.open = 0;
156                 if(--mouse.ref == 0){
157                         cursoroff(1);
158                         curs = arrow;
159                         Cursortocursor(&arrow);
160                         cursoron(1);
161                 }
162                 unlock(&mouse);
163         }
164 }
165
166
167 static long
168 mouseread(Chan *c, void *va, long n, vlong off)
169 {
170         char buf[4*12+1];
171         uchar *p;
172         static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 };
173         ulong offset = off;
174         Mousestate m;
175         int b;
176
177         p = va;
178         switch((ulong)c->qid.path){
179         case Qdir:
180                 return devdirread(c, va, n, mousedir, nelem(mousedir), devgen);
181
182         case Qcursor:
183                 if(offset != 0)
184                         return 0;
185                 if(n < 2*4+2*2*16)
186                         error(Eshort);
187                 n = 2*4+2*2*16;
188                 lock(&cursor);
189                 BPLONG(p+0, curs.offset.x);
190                 BPLONG(p+4, curs.offset.y);
191                 memmove(p+8, curs.clr, 2*16);
192                 memmove(p+40, curs.set, 2*16);
193                 unlock(&cursor);
194                 return n;
195
196         case Qmouse:
197                 while(mousechanged(0) == 0)
198                         rendsleep(&mouse.r, mousechanged, 0);
199
200                 mouse.qfull = 0;
201
202                 /*
203                  * No lock of the indicies is necessary here, because ri is only
204                  * updated by us, and there is only one mouse reader
205                  * at a time.  I suppose that more than one process
206                  * could try to read the fd at one time, but such behavior
207                  * is degenerate and already violates the calling
208                  * conventions for sleep above.
209                  */
210                 if(mouse.ri != mouse.wi){
211                         m = mouse.queue[mouse.ri];
212                         if(++mouse.ri == nelem(mouse.queue))
213                                 mouse.ri = 0;
214                 } else {
215                         lock(&cursor);
216         
217                         m = mouse.Mousestate;
218                         unlock(&cursor);
219                 }
220
221                 b = buttonmap[m.buttons&7];
222                 /* put buttons 4 and 5 back in */
223                 b |= m.buttons & (3<<3);
224                 sprint(buf, "m%11d %11d %11d %11lud",
225                         m.xy.x, m.xy.y,
226                         b,
227                         m.msec);
228                 mouse.lastcounter = m.counter;
229                 if(n > 1+4*12)
230                         n = 1+4*12;
231                 memmove(va, buf, n);
232                 return n;
233         }
234         return 0;
235 }
236
237 static void
238 setbuttonmap(char* map)
239 {
240         int i, x, one, two, three;
241
242         one = two = three = 0;
243         for(i = 0; i < 3; i++){
244                 if(map[i] == 0)
245                         error(Ebadarg);
246                 if(map[i] == '1'){
247                         if(one)
248                                 error(Ebadarg);
249                         one = 1<<i;
250                 }
251                 else if(map[i] == '2'){
252                         if(two)
253                                 error(Ebadarg);
254                         two = 1<<i;
255                 }
256                 else if(map[i] == '3'){
257                         if(three)
258                                 error(Ebadarg);
259                         three = 1<<i;
260                 }
261                 else
262                         error(Ebadarg);
263         }
264         if(map[i])
265                 error(Ebadarg);
266
267         memset(buttonmap, 0, 8);
268         for(i = 0; i < 8; i++){
269                 x = 0;
270                 if(i & 1)
271                         x |= one;
272                 if(i & 2)
273                         x |= two;
274                 if(i & 4)
275                         x |= three;
276                 buttonmap[x] = i;
277         }
278 }
279
280 static long
281 mousewrite(Chan *c, void *va, long n, vlong)
282 {
283         char *p;
284         Point pt;
285         char buf[64];
286
287         p = va;
288         switch((ulong)c->qid.path){
289         case Qdir:
290                 error(Eisdir);
291
292         case Qcursor:
293                 cursoroff(1);
294                 if(n < 2*4+2*2*16){
295                         curs = arrow;
296                         Cursortocursor(&arrow);
297                 }else{
298                         n = 2*4+2*2*16;
299                         curs.offset.x = BGLONG(p+0);
300                         curs.offset.y = BGLONG(p+4);
301                         memmove(curs.clr, p+8, 2*16);
302                         memmove(curs.set, p+40, 2*16);
303                         Cursortocursor(&curs);
304                 }
305                 qlock(&mouse);
306                 mouse.redraw = 1;
307                 mouseclock();
308                 qunlock(&mouse);
309                 cursoron(1);
310                 return n;
311
312         case Qmouse:
313                 if(n > sizeof buf-1)
314                         n = sizeof buf -1;
315                 memmove(buf, va, n);
316                 buf[n] = 0;
317                 p = 0;
318                 pt.x = strtoul(buf+1, &p, 0);
319                 if(p == 0)
320                         error(Eshort);
321                 pt.y = strtoul(p, 0, 0);
322                 qlock(&mouse);
323                 if(ptinrect(pt, gscreen->r)){
324                         mousetrack(pt.x, pt.y, mouse.buttons, nsec()/(1000*1000LL));
325                         mousewarpnote(pt);
326                 }
327                 qunlock(&mouse);
328                 return n;
329         }
330
331         error(Egreg);
332         return -1;
333 }
334
335 Dev mousedevtab = {
336         'm',
337         "mouse",
338
339         mousereset,
340         mouseinit,
341         mouseattach,
342         mousewalk,
343         mousestat,
344         mouseopen,
345         mousecreate,
346         mouseclose,
347         mouseread,
348         devbread,
349         mousewrite,
350         devbwrite,
351         devremove,
352         devwstat,
353 };
354
355 void
356 Cursortocursor(Cursor *c)
357 {
358         lock(&cursor);
359         memmove(&cursor.Cursor, c, sizeof(Cursor));
360         setcursor(c);
361         unlock(&cursor);
362 }
363
364 static int
365 scale(int x)
366 {
367         int sign = 1;
368
369         if(x < 0){
370                 sign = -1;
371                 x = -x;
372         }
373         switch(x){
374         case 0:
375         case 1:
376         case 2:
377         case 3:
378                 break;
379         case 4:
380                 x = 6 + (mouse.acceleration>>2);
381                 break;
382         case 5:
383                 x = 9 + (mouse.acceleration>>1);
384                 break;
385         default:
386                 x *= mouse.maxacc;
387                 break;
388         }
389         return sign*x;
390 }
391
392 static void
393 mouseclock(void)
394 {
395         lock(&cursor);
396         if(mouse.redraw){
397                 mouse.redraw = 0;
398                 cursoroff(0);
399                 mouse.redraw = cursoron(0);
400         }
401         unlock(&cursor);
402 }
403
404 /*
405  *  called at interrupt level to update the structure and
406  *  awaken any waiting procs.
407  */
408 void
409 mousetrack(int x, int y, int b, int msec)
410 {
411         int lastb;
412
413         lastb = mouse.buttons;
414         mouse.xy = Pt(x, y);
415         mouse.buttons = b;
416         mouse.redraw = 1;
417         mouse.counter++;
418         mouse.msec = msec;
419
420         /*
421          * if the queue fills, we discard the entire queue and don't
422          * queue any more events until a reader polls the mouse.
423          */
424         if(!mouse.qfull && lastb != b){ /* add to ring */
425                 mouse.queue[mouse.wi] = mouse.Mousestate;
426                 if(++mouse.wi == nelem(mouse.queue))
427                         mouse.wi = 0;
428                 if(mouse.wi == mouse.ri)
429                         mouse.qfull = 1;
430         }
431         rendwakeup(&mouse.r);
432         mouseclock();
433 }
434
435 int
436 mousechanged(void*)
437 {
438         return mouse.lastcounter != mouse.counter;
439 }
440
441 Point
442 mousexy(void)
443 {
444         return mouse.xy;
445 }
446
447 void
448 mouseaccelerate(int x)
449 {
450         mouse.acceleration = x;
451         if(mouse.acceleration < 3)
452                 mouse.maxacc = 2;
453         else
454                 mouse.maxacc = mouse.acceleration;
455 }