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