]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libdraw/event.c
Import sources from 2011-03-30 iso image
[plan9front.git] / sys / src / libdraw / event.c
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <cursor.h>
5 #include <event.h>
6
7 typedef struct  Slave Slave;
8 typedef struct  Ebuf Ebuf;
9
10 struct Slave
11 {
12         int     pid;
13         Ebuf    *head;          /* queue of messages for this descriptor */
14         Ebuf    *tail;
15         int     (*fn)(int, Event*, uchar*, int);
16 };
17
18 struct Ebuf
19 {
20         Ebuf    *next;
21         int     n;              /* number of bytes in buf */
22         uchar   buf[EMAXMSG];
23 };
24
25 static  Slave   eslave[MAXSLAVE];
26 static  int     Skeyboard = -1;
27 static  int     Smouse = -1;
28 static  int     Stimer = -1;
29 static  int     logfid;
30
31 static  int     nslave;
32 static  int     parentpid;
33 static  int     epipe[2];
34
35 static  int     eforkslave(ulong);
36 static  void    extract(void);
37 static  void    ekill(void);
38 static  int     enote(void *, char *);
39
40 static  int     mousefd;
41 static  int     cursorfd;
42
43 static
44 Ebuf*
45 ebread(Slave *s)
46 {
47         Ebuf *eb;
48         Dir *d;
49         ulong l;
50
51         for(;;){
52                 d = dirfstat(epipe[0]);
53                 if(d == nil)
54                         drawerror(display, "events: eread stat error");
55                 l = d->length;
56                 free(d);
57                 if(s->head && l==0)
58                         break;
59                 extract();
60         }
61         eb = s->head;
62         s->head = s->head->next;
63         if(s->head == 0)
64                 s->tail = 0;
65         return eb;
66 }
67
68 ulong
69 event(Event *e)
70 {
71         return eread(~0UL, e);
72 }
73
74 ulong
75 eread(ulong keys, Event *e)
76 {
77         Ebuf *eb;
78         int i, id;
79
80         if(keys == 0)
81                 return 0;
82         for(;;){
83                 for(i=0; i<nslave; i++)
84                         if((keys & (1<<i)) && eslave[i].head){
85                                 id = 1<<i;
86                                 if(i == Smouse)
87                                         e->mouse = emouse();
88                                 else if(i == Skeyboard)
89                                         e->kbdc = ekbd();
90                                 else if(i == Stimer)
91                                         eslave[i].head = 0;
92                                 else{
93                                         eb = ebread(&eslave[i]);
94                                         e->n = eb->n;
95                                         if(eslave[i].fn)
96                                                 id = (*eslave[i].fn)(id, e, eb->buf, eb->n);
97                                         else
98                                                 memmove(e->data, eb->buf, eb->n);
99                                         free(eb);
100                                 }
101                                 return id;
102                         }
103                 extract();
104         }
105 }
106
107 int
108 ecanmouse(void)
109 {
110         if(Smouse < 0)
111                 drawerror(display, "events: mouse not initialized");
112         return ecanread(Emouse);
113 }
114
115 int
116 ecankbd(void)
117 {
118         if(Skeyboard < 0)
119                 drawerror(display, "events: keyboard not initialzed");
120         return ecanread(Ekeyboard);
121 }
122
123 int
124 ecanread(ulong keys)
125 {
126         Dir *d;
127         int i;
128         ulong l;
129
130         for(;;){
131                 for(i=0; i<nslave; i++)
132                         if((keys & (1<<i)) && eslave[i].head)
133                                 return 1;
134                 d = dirfstat(epipe[0]);
135                 if(d == nil)
136                         drawerror(display, "events: ecanread stat error");
137                 l = d->length;
138                 free(d);
139                 if(l == 0)
140                         return 0;
141                 extract();
142         }
143 }
144
145 ulong
146 estartfn(ulong key, int fd, int n, int (*fn)(int, Event*, uchar*, int))
147 {
148         char buf[EMAXMSG+1];
149         int i, r;
150
151         if(fd < 0)
152                 drawerror(display, "events: bad file descriptor");
153         if(n <= 0 || n > EMAXMSG)
154                 n = EMAXMSG;
155         i = eforkslave(key);
156         if(i < MAXSLAVE){
157                 eslave[i].fn = fn;
158                 return 1<<i;
159         }
160         buf[0] = i - MAXSLAVE;
161         while((r = read(fd, buf+1, n))>0)
162                 if(write(epipe[1], buf, r+1)!=r+1)
163                         break;
164         buf[0] = MAXSLAVE;
165         write(epipe[1], buf, 1);
166         _exits(0);
167         return 0;
168 }
169
170 ulong
171 estart(ulong key, int fd, int n)
172 {
173         return estartfn(key, fd, n, nil);
174 }
175
176 ulong
177 etimer(ulong key, int n)
178 {
179         char t[2];
180
181         if(Stimer != -1)
182                 drawerror(display, "events: timer started twice");
183         Stimer = eforkslave(key);
184         if(Stimer < MAXSLAVE)
185                 return 1<<Stimer;
186         if(n <= 0)
187                 n = 1000;
188         t[0] = t[1] = Stimer - MAXSLAVE;
189         do
190                 sleep(n);
191         while(write(epipe[1], t, 2) == 2);
192         t[0] = MAXSLAVE;
193         write(epipe[1], t, 1);
194         _exits(0);
195         return 0;
196 }
197
198 static void
199 ekeyslave(int fd)
200 {
201         Rune r;
202         char t[3], k[10];
203         int kr, kn, w;
204
205         if(eforkslave(Ekeyboard) < MAXSLAVE)
206                 return;
207         kn = 0;
208         t[0] = Skeyboard;
209         for(;;){
210                 while(!fullrune(k, kn)){
211                         kr = read(fd, k+kn, sizeof k - kn);
212                         if(kr <= 0)
213                                 goto breakout;
214                         kn += kr;
215                 }
216                 w = chartorune(&r, k);
217                 kn -= w;
218                 memmove(k, &k[w], kn);
219                 t[1] = r;
220                 t[2] = r>>8;
221                 if(write(epipe[1], t, 3) != 3)
222                         break;
223         }
224 breakout:;
225         t[0] = MAXSLAVE;
226         write(epipe[1], t, 1);
227         _exits(0);
228 }
229
230 void
231 einit(ulong keys)
232 {
233         int ctl, fd;
234         char buf[256];
235
236         parentpid = getpid();
237         if(pipe(epipe) < 0)
238                 drawerror(display, "events: einit pipe");
239         atexit(ekill);
240         atnotify(enote, 1);
241         snprint(buf, sizeof buf, "%s/mouse", display->devdir);
242         mousefd = open(buf, ORDWR|OCEXEC);
243         if(mousefd < 0)
244                 drawerror(display, "einit: can't open mouse\n");
245         snprint(buf, sizeof buf, "%s/cursor", display->devdir);
246         cursorfd = open(buf, ORDWR|OCEXEC);
247         if(cursorfd < 0)
248                 drawerror(display, "einit: can't open cursor\n");
249         if(keys&Ekeyboard){
250                 snprint(buf, sizeof buf, "%s/cons", display->devdir);
251                 fd = open(buf, OREAD);
252                 if(fd < 0)
253                         drawerror(display, "events: can't open console");
254                 snprint(buf, sizeof buf, "%s/consctl", display->devdir);
255                 ctl = open("/dev/consctl", OWRITE|OCEXEC);
256                 if(ctl < 0)
257                         drawerror(display, "events: can't open consctl");
258                 write(ctl, "rawon", 5);
259                 for(Skeyboard=0; Ekeyboard & ~(1<<Skeyboard); Skeyboard++)
260                         ;
261                 ekeyslave(fd);
262         }
263         if(keys&Emouse){
264                 estart(Emouse, mousefd, 1+4*12);
265                 for(Smouse=0; Emouse & ~(1<<Smouse); Smouse++)
266                         ;
267         }
268 }
269
270 static void
271 extract(void)
272 {
273         Slave *s;
274         Ebuf *eb;
275         int i, n;
276         uchar ebuf[EMAXMSG+1];
277
278         /* avoid generating a message if there's nothing to show. */
279         /* this test isn't perfect, though; could do flushimage(display, 0) then call extract */
280         /* also: make sure we don't interfere if we're multiprocessing the display */
281         if(display->locking){
282                 /* if locking is being done by program, this means it can't depend on automatic flush in emouse() etc. */
283                 if(canqlock(&display->qlock)){
284                         if(display->bufp > display->buf)
285                                 flushimage(display, 1);
286                         unlockdisplay(display);
287                 }
288         }else
289                 if(display->bufp > display->buf)
290                         flushimage(display, 1);
291 loop:
292         if((n=read(epipe[0], ebuf, EMAXMSG+1)) < 0
293         || ebuf[0] >= MAXSLAVE)
294                 drawerror(display, "eof on event pipe");
295         if(n == 0)
296                 goto loop;
297         i = ebuf[0];
298         if(i >= nslave || n <= 1)
299                 drawerror(display, "events: protocol error: short read");
300         s = &eslave[i];
301         if(i == Stimer){
302                 s->head = (Ebuf *)1;
303                 return;
304         }
305         if(i == Skeyboard && n != 3)
306                 drawerror(display, "events: protocol error: keyboard");
307         if(i == Smouse){
308                 if(n < 1+1+2*12)
309                         drawerror(display, "events: protocol error: mouse");
310                 if(ebuf[1] == 'r')
311                         eresized(1);
312                 /* squash extraneous mouse events */
313                 if((eb=s->tail) && memcmp(eb->buf+1+2*12, ebuf+1+1+2*12, 12)==0){
314                         memmove(eb->buf, &ebuf[1], n - 1);
315                         return;
316                 }
317         }
318         /* try to save space by only allocating as much buffer as we need */
319         eb = malloc(sizeof(*eb) - sizeof(eb->buf) + n - 1);
320         if(eb == 0)
321                 drawerror(display, "events: protocol error 4");
322         eb->n = n - 1;
323         memmove(eb->buf, &ebuf[1], n - 1);
324         eb->next = 0;
325         if(s->head)
326                 s->tail = s->tail->next = eb;
327         else
328                 s->head = s->tail = eb;
329 }
330
331 static int
332 eforkslave(ulong key)
333 {
334         int i, pid;
335
336         for(i=0; i<MAXSLAVE; i++)
337                 if((key & ~(1<<i)) == 0 && eslave[i].pid == 0){
338                         if(nslave <= i)
339                                 nslave = i + 1;
340                         /*
341                          * share the file descriptors so the last child
342                          * out closes all connections to the window server.
343                          */
344                         switch(pid = rfork(RFPROC)){
345                         case 0:
346                                 return MAXSLAVE+i;
347                         case -1:
348                                 fprint(2, "events: fork error\n");
349                                 exits("fork");
350                         }
351                         eslave[i].pid = pid;
352                         eslave[i].head = eslave[i].tail = 0;
353                         return i;
354                 }
355         drawerror(display, "events: bad slave assignment");
356         return 0;
357 }
358
359 static int
360 enote(void *v, char *s)
361 {
362         char t[1];
363         int i, pid;
364
365         USED(v, s);
366         pid = getpid();
367         if(pid != parentpid){
368                 for(i=0; i<nslave; i++){
369                         if(pid == eslave[i].pid){
370                                 t[0] = MAXSLAVE;
371                                 write(epipe[1], t, 1);
372                                 break;
373                         }
374                 }
375                 return 0;
376         }
377         close(epipe[0]);
378         epipe[0] = -1;
379         close(epipe[1]);
380         epipe[1] = -1;
381         for(i=0; i<nslave; i++){
382                 if(pid == eslave[i].pid)
383                         continue;       /* don't kill myself */
384                 postnote(PNPROC, eslave[i].pid, "die");
385         }
386         return 0;
387 }
388
389 static void
390 ekill(void)
391 {
392         enote(0, 0);
393 }
394
395 Mouse
396 emouse(void)
397 {
398         Mouse m;
399         Ebuf *eb;
400         static but[2];
401         int b;
402
403         if(Smouse < 0)
404                 drawerror(display, "events: mouse not initialized");
405         eb = ebread(&eslave[Smouse]);
406         m.xy.x = atoi((char*)eb->buf+1+0*12);
407         m.xy.y = atoi((char*)eb->buf+1+1*12);
408         b = atoi((char*)eb->buf+1+2*12);
409         m.buttons = b;
410         m.msec = atoi((char*)eb->buf+1+3*12);
411         if (logfid)
412                 fprint(logfid, "b: %d xy: %P\n", m.buttons, m.xy);
413         free(eb);
414         return m;
415 }
416
417 int
418 ekbd(void)
419 {
420         Ebuf *eb;
421         int c;
422
423         if(Skeyboard < 0)
424                 drawerror(display, "events: keyboard not initialzed");
425         eb = ebread(&eslave[Skeyboard]);
426         c = eb->buf[0] + (eb->buf[1]<<8);
427         free(eb);
428         return c;
429 }
430
431 void
432 emoveto(Point pt)
433 {
434         char buf[2*12+2];
435         int n;
436
437         n = sprint(buf, "m%d %d", pt.x, pt.y);
438         write(mousefd, buf, n);
439 }
440
441 void
442 esetcursor(Cursor *c)
443 {
444         uchar curs[2*4+2*2*16];
445
446         if(c == 0)
447                 write(cursorfd, curs, 0);
448         else{
449                 BPLONG(curs+0*4, c->offset.x);
450                 BPLONG(curs+1*4, c->offset.y);
451                 memmove(curs+2*4, c->clr, 2*2*16);
452                 write(cursorfd, curs, sizeof curs);
453         }
454 }
455
456 int
457 ereadmouse(Mouse *m)
458 {
459         int n;
460         char buf[128];
461
462         do{
463                 n = read(mousefd, buf, sizeof(buf));
464                 if(n < 0)       /* probably interrupted */
465                         return -1;
466                 n = eatomouse(m, buf, n);
467         }while(n == 0);
468         return n;
469 }
470
471 int
472 eatomouse(Mouse *m, char *buf, int n)
473 {
474         if(n != 1+4*12){
475                 werrstr("atomouse: bad count");
476                 return -1;
477         }
478
479         if(buf[0] == 'r')
480                 eresized(1);
481         m->xy.x = atoi(buf+1+0*12);
482         m->xy.y = atoi(buf+1+1*12);
483         m->buttons = atoi(buf+1+2*12);
484         m->msec = atoi(buf+1+3*12);
485         return n;
486 }