tevent.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
tevent.c (7535B) | |
--- | |
1 #include <u.h> | |
2 #include <sys/select.h> | |
3 #include <libc.h> | |
4 #include <draw.h> | |
5 #include <cursor.h> | |
6 #include <event.h> | |
7 #include <mux.h> | |
8 #include <drawfcall.h> | |
9 | |
10 typedef struct Slave Slave; | |
11 typedef struct Ebuf Ebuf; | |
12 extern Mouse _drawmouse; | |
13 | |
14 struct Slave | |
15 { | |
16 int inuse; | |
17 Ebuf *head; /* queue of messages for this … | |
18 Ebuf *tail; | |
19 int (*fn)(int, Event*, uchar*, int); | |
20 Muxrpc *rpc; | |
21 vlong nexttick; | |
22 int fd; | |
23 int n; | |
24 }; | |
25 | |
26 struct Ebuf | |
27 { | |
28 Ebuf *next; | |
29 int n; /* number of bytes in buf */ | |
30 union { | |
31 uchar buf[EMAXMSG]; | |
32 Rune rune; | |
33 Mouse mouse; | |
34 } u; | |
35 }; | |
36 | |
37 static Slave eslave[MAXSLAVE]; | |
38 static int Skeyboard = -1; | |
39 static int Smouse = -1; | |
40 static int Stimer = -1; | |
41 | |
42 static int nslave; | |
43 static int newkey(ulong); | |
44 static int extract(int canblock); | |
45 | |
46 static | |
47 Ebuf* | |
48 ebread(Slave *s) | |
49 { | |
50 Ebuf *eb; | |
51 | |
52 while(!s->head) | |
53 extract(1); | |
54 eb = s->head; | |
55 s->head = s->head->next; | |
56 if(s->head == 0) | |
57 s->tail = 0; | |
58 return eb; | |
59 } | |
60 | |
61 ulong | |
62 event(Event *e) | |
63 { | |
64 return eread(~0UL, e); | |
65 } | |
66 | |
67 ulong | |
68 eread(ulong keys, Event *e) | |
69 { | |
70 Ebuf *eb; | |
71 int i, id; | |
72 | |
73 if(keys == 0) | |
74 return 0; | |
75 for(;;){ | |
76 for(i=0; i<nslave; i++) | |
77 if((keys & (1<<i)) && eslave[i].head){ | |
78 id = 1<<i; | |
79 if(i == Smouse) | |
80 e->mouse = emouse(); | |
81 else if(i == Skeyboard) | |
82 e->kbdc = ekbd(); | |
83 else if(i == Stimer) | |
84 eslave[i].head = 0; | |
85 else{ | |
86 eb = ebread(&eslave[i]); | |
87 e->n = eb->n; | |
88 if(eslave[i].fn) | |
89 id = (*eslave[i].fn)(id,… | |
90 else | |
91 memmove(e->data, eb->u.b… | |
92 free(eb); | |
93 } | |
94 return id; | |
95 } | |
96 extract(1); | |
97 } | |
98 return 0; | |
99 } | |
100 | |
101 int | |
102 ecanmouse(void) | |
103 { | |
104 if(Smouse < 0) | |
105 drawerror(display, "events: mouse not initialized"); | |
106 return ecanread(Emouse); | |
107 } | |
108 | |
109 int | |
110 ecankbd(void) | |
111 { | |
112 if(Skeyboard < 0) | |
113 drawerror(display, "events: keyboard not initialzed"); | |
114 return ecanread(Ekeyboard); | |
115 } | |
116 | |
117 int | |
118 ecanread(ulong keys) | |
119 { | |
120 int i; | |
121 | |
122 for(;;){ | |
123 for(i=0; i<nslave; i++) | |
124 if((keys & (1<<i)) && eslave[i].head) | |
125 return 1; | |
126 if(!extract(0)) | |
127 return 0; | |
128 } | |
129 return -1; | |
130 } | |
131 | |
132 ulong | |
133 estartfn(ulong key, int fd, int n, int (*fn)(int, Event*, uchar*, int)) | |
134 { | |
135 int i; | |
136 | |
137 if(fd < 0) | |
138 drawerror(display, "events: bad file descriptor"); | |
139 if(n <= 0 || n > EMAXMSG) | |
140 n = EMAXMSG; | |
141 i = newkey(key); | |
142 eslave[i].fn = fn; | |
143 eslave[i].fd = fd; | |
144 eslave[i].n = n; | |
145 return 1<<i; | |
146 } | |
147 | |
148 ulong | |
149 estart(ulong key, int fd, int n) | |
150 { | |
151 return estartfn(key, fd, n, nil); | |
152 } | |
153 | |
154 ulong | |
155 etimer(ulong key, int n) | |
156 { | |
157 if(Stimer != -1) | |
158 drawerror(display, "events: timer started twice"); | |
159 Stimer = newkey(key); | |
160 if(n <= 0) | |
161 n = 1000; | |
162 eslave[Stimer].n = n; | |
163 eslave[Stimer].nexttick = nsec()+n*1000000LL; | |
164 return 1<<Stimer; | |
165 } | |
166 | |
167 void | |
168 einit(ulong keys) | |
169 { | |
170 if(keys&Ekeyboard){ | |
171 for(Skeyboard=0; Ekeyboard & ~(1<<Skeyboard); Skeyboard+… | |
172 ; | |
173 eslave[Skeyboard].inuse = 1; | |
174 if(nslave <= Skeyboard) | |
175 nslave = Skeyboard+1; | |
176 } | |
177 if(keys&Emouse){ | |
178 for(Smouse=0; Emouse & ~(1<<Smouse); Smouse++) | |
179 ; | |
180 eslave[Smouse].inuse = 1; | |
181 if(nslave <= Smouse) | |
182 nslave = Smouse+1; | |
183 } | |
184 } | |
185 | |
186 static Ebuf* | |
187 newebuf(Slave *s, int n) | |
188 { | |
189 Ebuf *eb; | |
190 | |
191 eb = malloc(sizeof(*eb) - sizeof(eb->u.buf) + n); | |
192 if(eb == nil) | |
193 drawerror(display, "events: out of memory"); | |
194 eb->n = n; | |
195 eb->next = 0; | |
196 if(s->head) | |
197 s->tail = s->tail->next = eb; | |
198 else | |
199 s->head = s->tail = eb; | |
200 return eb; | |
201 } | |
202 | |
203 static Muxrpc* | |
204 startrpc(int type) | |
205 { | |
206 uchar buf[100]; | |
207 Wsysmsg w; | |
208 | |
209 w.type = type; | |
210 convW2M(&w, buf, sizeof buf); | |
211 return muxrpcstart(display->mux, buf); | |
212 } | |
213 | |
214 static int | |
215 finishrpc(Muxrpc *r, Wsysmsg *w) | |
216 { | |
217 uchar *p; | |
218 void *v; | |
219 int n; | |
220 | |
221 if(!muxrpccanfinish(r, &v)) | |
222 return 0; | |
223 p = v; | |
224 if(p == nil) /* eof on connection */ | |
225 exit(0); | |
226 GET(p, n); | |
227 convM2W(p, n, w); | |
228 free(p); | |
229 return 1; | |
230 } | |
231 | |
232 static int | |
233 extract(int canblock) | |
234 { | |
235 Ebuf *eb; | |
236 int i, n, max; | |
237 fd_set rset, wset, xset; | |
238 struct timeval tv, *timeout; | |
239 Wsysmsg w; | |
240 vlong t0; | |
241 | |
242 /* | |
243 * Flush draw buffer before waiting for responses. | |
244 * Avoid doing so if buffer is empty. | |
245 * Also make sure that we don't interfere with app-specific lock… | |
246 */ | |
247 if(display->locking){ | |
248 /* | |
249 * if locking is being done by program, | |
250 * this means it can't depend on automatic | |
251 * flush in emouse() etc. | |
252 */ | |
253 if(canqlock(&display->qlock)){ | |
254 if(display->bufp > display->buf) | |
255 flushimage(display, 1); | |
256 unlockdisplay(display); | |
257 } | |
258 }else | |
259 if(display->bufp > display->buf) | |
260 flushimage(display, 1); | |
261 | |
262 /* | |
263 * Set up for select. | |
264 */ | |
265 FD_ZERO(&rset); | |
266 FD_ZERO(&wset); | |
267 FD_ZERO(&xset); | |
268 max = -1; | |
269 timeout = nil; | |
270 for(i=0; i<nslave; i++){ | |
271 if(!eslave[i].inuse) | |
272 continue; | |
273 if(i == Smouse){ | |
274 if(eslave[i].rpc == nil) | |
275 eslave[i].rpc = startrpc(Trdmouse); | |
276 if(eslave[i].rpc){ | |
277 /* if ready, don't block in select */ | |
278 if(eslave[i].rpc->p) | |
279 canblock = 0; | |
280 FD_SET(display->srvfd, &rset); | |
281 FD_SET(display->srvfd, &xset); | |
282 if(display->srvfd > max) | |
283 max = display->srvfd; | |
284 } | |
285 }else if(i == Skeyboard){ | |
286 if(eslave[i].rpc == nil) | |
287 eslave[i].rpc = startrpc(Trdkbd4); | |
288 if(eslave[i].rpc){ | |
289 /* if ready, don't block in select */ | |
290 if(eslave[i].rpc->p) | |
291 canblock = 0; | |
292 FD_SET(display->srvfd, &rset); | |
293 FD_SET(display->srvfd, &xset); | |
294 if(display->srvfd > max) | |
295 max = display->srvfd; | |
296 } | |
297 }else if(i == Stimer){ | |
298 t0 = nsec(); | |
299 if(t0 >= eslave[i].nexttick){ | |
300 tv.tv_sec = 0; | |
301 tv.tv_usec = 0; | |
302 }else{ | |
303 tv.tv_sec = (eslave[i].nexttick-t0)/1000… | |
304 tv.tv_usec = (eslave[i].nexttick-t0)%100… | |
305 } | |
306 timeout = &tv; | |
307 }else{ | |
308 FD_SET(eslave[i].fd, &rset); | |
309 FD_SET(eslave[i].fd, &xset); | |
310 if(eslave[i].fd > max) | |
311 max = eslave[i].fd; | |
312 } | |
313 } | |
314 | |
315 if(!canblock){ | |
316 tv.tv_sec = 0; | |
317 tv.tv_usec = 0; | |
318 timeout = &tv; | |
319 } | |
320 | |
321 if(select(max+1, &rset, &wset, &xset, timeout) < 0) | |
322 drawerror(display, "select failure"); | |
323 | |
324 /* | |
325 * Look to see what can proceed. | |
326 */ | |
327 n = 0; | |
328 for(i=0; i<nslave; i++){ | |
329 if(!eslave[i].inuse) | |
330 continue; | |
331 if(i == Smouse){ | |
332 if(finishrpc(eslave[i].rpc, &w)){ | |
333 eslave[i].rpc = nil; | |
334 eb = newebuf(&eslave[i], sizeof(Mouse)); | |
335 _drawmouse = w.mouse; | |
336 eb->u.mouse = w.mouse; | |
337 if(w.resized) | |
338 eresized(1); | |
339 n++; | |
340 } | |
341 }else if(i == Skeyboard){ | |
342 if(finishrpc(eslave[i].rpc, &w)){ | |
343 eslave[i].rpc = nil; | |
344 eb = newebuf(&eslave[i], sizeof(Rune)+2)… | |
345 eb->u.rune = w.rune; | |
346 n++; | |
347 } | |
348 }else if(i == Stimer){ | |
349 t0 = nsec(); | |
350 while(t0 > eslave[i].nexttick){ | |
351 eslave[i].nexttick += eslave[i].n*100000… | |
352 eslave[i].head = (Ebuf*)1; | |
353 n++; | |
354 } | |
355 }else{ | |
356 if(FD_ISSET(eslave[i].fd, &rset)){ | |
357 eb = newebuf(&eslave[i], eslave[i].n); | |
358 eb->n = read(eslave[i].fd, eb->u.buf, es… | |
359 n++; | |
360 } | |
361 } | |
362 } | |
363 return n; | |
364 } | |
365 | |
366 static int | |
367 newkey(ulong key) | |
368 { | |
369 int i; | |
370 | |
371 for(i=0; i<MAXSLAVE; i++) | |
372 if((key & ~(1<<i)) == 0 && eslave[i].inuse == 0){ | |
373 if(nslave <= i) | |
374 nslave = i + 1; | |
375 eslave[i].inuse = 1; | |
376 return i; | |
377 } | |
378 drawerror(display, "events: bad slave assignment"); | |
379 return 0; | |
380 } | |
381 | |
382 Mouse | |
383 emouse(void) | |
384 { | |
385 Mouse m; | |
386 Ebuf *eb; | |
387 | |
388 if(Smouse < 0) | |
389 drawerror(display, "events: mouse not initialized"); | |
390 eb = ebread(&eslave[Smouse]); | |
391 m = eb->u.mouse; | |
392 free(eb); | |
393 return m; | |
394 } | |
395 | |
396 int | |
397 ekbd(void) | |
398 { | |
399 Ebuf *eb; | |
400 int c; | |
401 | |
402 if(Skeyboard < 0) | |
403 drawerror(display, "events: keyboard not initialzed"); | |
404 eb = ebread(&eslave[Skeyboard]); | |
405 c = eb->u.rune; | |
406 free(eb); | |
407 return c; | |
408 } | |
409 | |
410 void | |
411 emoveto(Point pt) | |
412 { | |
413 _displaymoveto(display, pt); | |
414 } | |
415 | |
416 void | |
417 esetcursor(Cursor *c) | |
418 { | |
419 _displaycursor(display, c, nil); | |
420 } | |
421 | |
422 void | |
423 esetcursor2(Cursor *c, Cursor2 *c2) | |
424 { | |
425 _displaycursor(display, c, c2); | |
426 } | |
427 | |
428 int | |
429 ereadmouse(Mouse *m) | |
430 { | |
431 int resized; | |
432 | |
433 resized = 0; | |
434 if(_displayrdmouse(display, m, &resized) < 0) | |
435 return -1; | |
436 if(resized) | |
437 eresized(1); | |
438 return 1; | |
439 } |