Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <cursor.h>
5 #include <event.h>
7 typedef struct Slave Slave;
8 typedef struct Ebuf Ebuf;
10 struct Slave
11 {
12 int pid;
13 Ebuf *head; /* ueue of messages for this descriptor */
14 Ebuf *tail;
15 int (*fn)(int, Event*, uchar*, int);
16 };
18 struct Ebuf
19 {
20 Ebuf *next;
21 int n; /* number of bytes in buf */
22 uchar buf[EMAXMSG];
23 };
25 static Slave eslave[MAXSLAVE];
26 static int Skeyboard = -1;
27 static int Smouse = -1;
28 static int Stimer = -1;
29 static int logfid;
31 static int nslave;
32 static int parentpid;
33 static int epipe[2];
34 static int eforkslave(ulong);
35 static void extract(void);
36 static void ekill(void);
37 static int enote(void *, char *);
38 static int mousefd;
39 static int cursorfd;
41 static
42 Ebuf*
43 ebread(Slave *s)
44 {
45 Ebuf *eb;
46 Dir *d;
47 ulong l;
49 for(;;){
50 d = dirfstat(epipe[0]);
51 if(d == nil)
52 drawerror(display, "events: eread stat error");
53 l = d->length;
54 free(d);
55 if(s->head && l==0)
56 break;
57 extract();
58 }
59 eb = s->head;
60 s->head = s->head->next;
61 if(s->head == 0)
62 s->tail = 0;
63 return eb;
64 }
66 ulong
67 event(Event *e)
68 {
69 return eread(~0UL, e);
70 }
72 ulong
73 eread(ulong keys, Event *e)
74 {
75 Ebuf *eb;
76 int i, id;
78 if(keys == 0)
79 return 0;
80 for(;;){
81 for(i=0; i<nslave; i++)
82 if((keys & (1<<i)) && eslave[i].head){
83 id = 1<<i;
84 if(i == Smouse)
85 e->mouse = emouse();
86 else if(i == Skeyboard)
87 e->kbdc = ekbd();
88 else if(i == Stimer)
89 eslave[i].head = 0;
90 else{
91 eb = ebread(&eslave[i]);
92 e->n = eb->n;
93 if(eslave[i].fn)
94 id = (*eslave[i].fn)(id, e, eb->buf, eb->n);
95 else
96 memmove(e->data, eb->buf, eb->n);
97 free(eb);
98 }
99 return id;
101 extract();
103 return 0;
106 int
107 ecanmouse(void)
109 if(Smouse < 0)
110 drawerror(display, "events: mouse not initialized");
111 return ecanread(Emouse);
114 int
115 ecankbd(void)
117 if(Skeyboard < 0)
118 drawerror(display, "events: keyboard not initialzed");
119 return ecanread(Ekeyboard);
122 int
123 ecanread(ulong keys)
125 Dir *d;
126 int i;
127 ulong l;
129 for(;;){
130 for(i=0; i<nslave; i++)
131 if((keys & (1<<i)) && eslave[i].head)
132 return 1;
133 d = dirfstat(epipe[0]);
134 if(d == nil)
135 drawerror(display, "events: ecanread stat error");
136 l = d->length;
137 free(d);
138 if(l == 0)
139 return 0;
140 extract();
142 return -1;
145 ulong
146 estartfn(ulong key, int fd, int n, int (*fn)(int, Event*, uchar*, int))
148 char buf[EMAXMSG+1];
149 int i, r;
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;
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;
170 ulong
171 estart(ulong key, int fd, int n)
173 return estartfn(key, fd, n, nil);
176 ulong
177 etimer(ulong key, int n)
179 char t[2];
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;
198 static void
199 ekeyslave(int fd)
201 Rune r;
202 char t[3], k[10];
203 int kr, kn, w;
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;
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;
224 breakout:;
225 t[0] = MAXSLAVE;
226 write(epipe[1], t, 1);
227 _exits(0);
230 void
231 einit(ulong keys)
233 int ctl, fd;
234 char buf[256];
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++)
261 ekeyslave(fd);
263 if(keys&Emouse){
264 estart(Emouse, mousefd, 1+4*12);
265 for(Smouse=0; Emouse & ~(1<<Smouse); Smouse++)
270 static void
271 extract(void)
273 Slave *s;
274 Ebuf *eb;
275 int i, n;
276 uchar ebuf[EMAXMSG+1];
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);
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;
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;
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;
331 static int
332 eforkslave(ulong key)
334 int i, pid;
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");
351 eslave[i].pid = pid;
352 eslave[i].head = eslave[i].tail = 0;
353 return i;
355 drawerror(display, "events: bad slave assignment");
356 return 0;
359 static int
360 enote(void *v, char *s)
362 char t[1];
363 int i, pid;
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;
375 return 0;
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");
386 return 0;
389 static void
390 ekill(void)
392 enote(0, 0);
395 Mouse
396 emouse(void)
398 Mouse m;
399 Ebuf *eb;
400 static but[2];
401 int b;
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&7;
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;
417 int
418 ekbd(void)
420 Ebuf *eb;
421 int c;
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;
431 void
432 emoveto(Point pt)
434 char buf[2*12+2];
435 int n;
437 n = sprint(buf, "m%d %d", pt.x, pt.y);
438 write(mousefd, buf, n);
441 void
442 esetcursor(Cursor *c)
444 uchar curs[2*4+2*2*16];
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);
456 int
457 ereadmouse(Mouse *m)
459 int n;
460 char buf[128];
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;
471 int
472 eatomouse(Mouse *m, char *buf, int n)
474 if(n != 1+4*12){
475 werrstr("atomouse: bad count");
476 return -1;
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;