]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libdraw/event.c
fix utf and rune handling in preparation for 32bit runes
[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[1+UTFmax], 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(t+1, k, w);
219                 memmove(k, &k[w], kn);
220                 if(write(epipe[1], t, sizeof(t)) != sizeof(t))
221                         break;
222         }
223 breakout:;
224         t[0] = MAXSLAVE;
225         write(epipe[1], t, 1);
226         _exits(0);
227 }
228
229 void
230 einit(ulong keys)
231 {
232         int ctl, fd;
233         char buf[256];
234
235         parentpid = getpid();
236         if(pipe(epipe) < 0)
237                 drawerror(display, "events: einit pipe");
238         atexit(ekill);
239         atnotify(enote, 1);
240         snprint(buf, sizeof buf, "%s/mouse", display->devdir);
241         mousefd = open(buf, ORDWR|OCEXEC);
242         if(mousefd < 0)
243                 drawerror(display, "einit: can't open mouse\n");
244         snprint(buf, sizeof buf, "%s/cursor", display->devdir);
245         cursorfd = open(buf, ORDWR|OCEXEC);
246         if(cursorfd < 0)
247                 drawerror(display, "einit: can't open cursor\n");
248         if(keys&Ekeyboard){
249                 snprint(buf, sizeof buf, "%s/cons", display->devdir);
250                 fd = open(buf, OREAD);
251                 if(fd < 0)
252                         drawerror(display, "events: can't open console");
253                 snprint(buf, sizeof buf, "%s/consctl", display->devdir);
254                 ctl = open("/dev/consctl", OWRITE|OCEXEC);
255                 if(ctl < 0)
256                         drawerror(display, "events: can't open consctl");
257                 write(ctl, "rawon", 5);
258                 for(Skeyboard=0; Ekeyboard & ~(1<<Skeyboard); Skeyboard++)
259                         ;
260                 ekeyslave(fd);
261         }
262         if(keys&Emouse){
263                 estart(Emouse, mousefd, 1+4*12);
264                 for(Smouse=0; Emouse & ~(1<<Smouse); Smouse++)
265                         ;
266         }
267 }
268
269 static void
270 extract(void)
271 {
272         Slave *s;
273         Ebuf *eb;
274         int i, n;
275         uchar ebuf[EMAXMSG+1];
276
277         /* avoid generating a message if there's nothing to show. */
278         /* this test isn't perfect, though; could do flushimage(display, 0) then call extract */
279         /* also: make sure we don't interfere if we're multiprocessing the display */
280         if(display->locking){
281                 /* if locking is being done by program, this means it can't depend on automatic flush in emouse() etc. */
282                 if(canqlock(&display->qlock)){
283                         if(display->bufp > display->buf)
284                                 flushimage(display, 1);
285                         unlockdisplay(display);
286                 }
287         }else
288                 if(display->bufp > display->buf)
289                         flushimage(display, 1);
290 loop:
291         if((n=read(epipe[0], ebuf, EMAXMSG+1)) < 0
292         || ebuf[0] >= MAXSLAVE)
293                 drawerror(display, "eof on event pipe");
294         if(n == 0)
295                 goto loop;
296         i = ebuf[0];
297         if(i >= nslave || n <= 1)
298                 drawerror(display, "events: protocol error: short read");
299         s = &eslave[i];
300         if(i == Stimer){
301                 s->head = (Ebuf *)1;
302                 return;
303         }
304         if(i == Skeyboard && n != (1+UTFmax))
305                 drawerror(display, "events: protocol error: keyboard");
306         if(i == Smouse){
307                 if(n < 1+1+2*12)
308                         drawerror(display, "events: protocol error: mouse");
309                 if(ebuf[1] == 'r')
310                         eresized(1);
311                 /* squash extraneous mouse events */
312                 if((eb=s->tail) && memcmp(eb->buf+1+2*12, ebuf+1+1+2*12, 12)==0){
313                         memmove(eb->buf, &ebuf[1], n - 1);
314                         return;
315                 }
316         }
317         /* try to save space by only allocating as much buffer as we need */
318         eb = malloc(sizeof(*eb) - sizeof(eb->buf) + n - 1);
319         if(eb == 0)
320                 drawerror(display, "events: protocol error 4");
321         eb->n = n - 1;
322         memmove(eb->buf, &ebuf[1], n - 1);
323         eb->next = 0;
324         if(s->head)
325                 s->tail = s->tail->next = eb;
326         else
327                 s->head = s->tail = eb;
328 }
329
330 static int
331 eforkslave(ulong key)
332 {
333         int i, pid;
334
335         for(i=0; i<MAXSLAVE; i++)
336                 if((key & ~(1<<i)) == 0 && eslave[i].pid == 0){
337                         if(nslave <= i)
338                                 nslave = i + 1;
339                         /*
340                          * share the file descriptors so the last child
341                          * out closes all connections to the window server.
342                          */
343                         switch(pid = rfork(RFPROC)){
344                         case 0:
345                                 return MAXSLAVE+i;
346                         case -1:
347                                 fprint(2, "events: fork error\n");
348                                 exits("fork");
349                         }
350                         eslave[i].pid = pid;
351                         eslave[i].head = eslave[i].tail = 0;
352                         return i;
353                 }
354         drawerror(display, "events: bad slave assignment");
355         return 0;
356 }
357
358 static int
359 enote(void *v, char *s)
360 {
361         char t[1];
362         int i, pid;
363
364         USED(v, s);
365         pid = getpid();
366         if(pid != parentpid){
367                 for(i=0; i<nslave; i++){
368                         if(pid == eslave[i].pid){
369                                 t[0] = MAXSLAVE;
370                                 write(epipe[1], t, 1);
371                                 break;
372                         }
373                 }
374                 return 0;
375         }
376         close(epipe[0]);
377         epipe[0] = -1;
378         close(epipe[1]);
379         epipe[1] = -1;
380         for(i=0; i<nslave; i++){
381                 if(pid == eslave[i].pid)
382                         continue;       /* don't kill myself */
383                 postnote(PNPROC, eslave[i].pid, "die");
384         }
385         return 0;
386 }
387
388 static void
389 ekill(void)
390 {
391         enote(0, 0);
392 }
393
394 Mouse
395 emouse(void)
396 {
397         Mouse m;
398         Ebuf *eb;
399         static but[2];
400         int b;
401
402         if(Smouse < 0)
403                 drawerror(display, "events: mouse not initialized");
404         eb = ebread(&eslave[Smouse]);
405         m.xy.x = atoi((char*)eb->buf+1+0*12);
406         m.xy.y = atoi((char*)eb->buf+1+1*12);
407         b = atoi((char*)eb->buf+1+2*12);
408         m.buttons = b;
409         m.msec = atoi((char*)eb->buf+1+3*12);
410         if (logfid)
411                 fprint(logfid, "b: %d xy: %P\n", m.buttons, m.xy);
412         free(eb);
413         return m;
414 }
415
416 int
417 ekbd(void)
418 {
419         Ebuf *eb;
420         Rune r;
421
422         if(Skeyboard < 0)
423                 drawerror(display, "events: keyboard not initialzed");
424         eb = ebread(&eslave[Skeyboard]);
425         chartorune(&r, (char*)eb->buf);
426         return r;
427 }
428
429 void
430 emoveto(Point pt)
431 {
432         char buf[2*12+2];
433         int n;
434
435         n = sprint(buf, "m%d %d", pt.x, pt.y);
436         write(mousefd, buf, n);
437 }
438
439 void
440 esetcursor(Cursor *c)
441 {
442         uchar curs[2*4+2*2*16];
443
444         if(c == 0)
445                 write(cursorfd, curs, 0);
446         else{
447                 BPLONG(curs+0*4, c->offset.x);
448                 BPLONG(curs+1*4, c->offset.y);
449                 memmove(curs+2*4, c->clr, 2*2*16);
450                 write(cursorfd, curs, sizeof curs);
451         }
452 }
453
454 int
455 ereadmouse(Mouse *m)
456 {
457         int n;
458         char buf[128];
459
460         do{
461                 n = read(mousefd, buf, sizeof(buf));
462                 if(n < 0)       /* probably interrupted */
463                         return -1;
464                 n = eatomouse(m, buf, n);
465         }while(n == 0);
466         return n;
467 }
468
469 int
470 eatomouse(Mouse *m, char *buf, int n)
471 {
472         if(n != 1+4*12){
473                 werrstr("atomouse: bad count");
474                 return -1;
475         }
476
477         if(buf[0] == 'r')
478                 eresized(1);
479         m->xy.x = atoi(buf+1+0*12);
480         m->xy.y = atoi(buf+1+1*12);
481         m->buttons = atoi(buf+1+2*12);
482         m->msec = atoi(buf+1+3*12);
483         return n;
484 }