Blob


1 /* Copyright (c) 2006 Russ Cox */
3 #include <u.h>
4 #include <sys/select.h>
5 #include <libc.h>
6 #include <draw.h>
7 #include <mouse.h>
8 #include <cursor.h>
9 #include <drawfcall.h>
10 #include <mux.h>
12 int chattydrawclient;
14 static int drawgettag(Mux *mux, void *vmsg);
15 static void* drawrecv(Mux *mux);
16 static int drawnbrecv(Mux *mux, void**);
17 static int drawsend(Mux *mux, void *vmsg);
18 static int drawsettag(Mux *mux, void *vmsg, uint tag);
19 static int canreadfd(int);
21 int
22 _displayconnect(Display *d)
23 {
24 int pid, p[2];
26 fmtinstall('W', drawfcallfmt);
27 fmtinstall('H', encodefmt);
29 if(pipe(p) < 0)
30 return -1;
31 if((pid=fork()) < 0){
32 close(p[0]);
33 close(p[1]);
34 return -1;
35 }
36 if(pid == 0){
37 close(p[0]);
38 dup(p[1], 0);
39 dup(p[1], 1);
40 /* execl("strace", "strace", "-o", "drawsrv.out", "drawsrv", nil); */
41 /*
42 * The argv0 has no meaning to devdraw.
43 * Pass it along only so that the various
44 * devdraws in psu -a can be distinguished.
45 */
46 execl("devdraw", "devdraw", argv0, nil);
47 sysfatal("exec devdraw: %r");
48 }
49 close(p[1]);
50 d->srvfd = p[0];
51 return 0;
52 }
54 int
55 _displaymux(Display *d)
56 {
57 if((d->mux = mallocz(sizeof(*d->mux), 1)) == nil)
58 return -1;
60 d->mux->mintag = 1;
61 d->mux->maxtag = 255;
62 d->mux->send = drawsend;
63 d->mux->recv = drawrecv;
64 d->mux->nbrecv = drawnbrecv;
65 d->mux->gettag = drawgettag;
66 d->mux->settag = drawsettag;
67 d->mux->aux = d;
68 muxinit(d->mux);
70 return 0;
71 }
73 static int
74 drawsend(Mux *mux, void *vmsg)
75 {
76 int n;
77 uchar *msg;
78 Display *d;
80 msg = vmsg;
81 GET(msg, n);
82 d = mux->aux;
83 return write(d->srvfd, msg, n);
84 }
86 static int
87 _drawrecv(Mux *mux, int canblock, void **vp)
88 {
89 int n;
90 uchar buf[4], *p;
91 Display *d;
93 d = mux->aux;
94 *vp = nil;
95 if(!canblock && !canreadfd(d->srvfd))
96 return 0;
97 if((n=readn(d->srvfd, buf, 4)) != 4)
98 return 1;
99 GET(buf, n);
100 p = malloc(n);
101 if(p == nil){
102 fprint(2, "out of memory allocating %d in drawrecv\n", n);
103 return 1;
105 memmove(p, buf, 4);
106 if(readn(d->srvfd, p+4, n-4) != n-4){
107 free(p);
108 return 1;
110 *vp = p;
111 return 1;
114 static void*
115 drawrecv(Mux *mux)
117 void *p;
118 _drawrecv(mux, 1, &p);
119 return p;
122 static int
123 drawnbrecv(Mux *mux, void **vp)
125 return _drawrecv(mux, 0, vp);
128 static int
129 drawgettag(Mux *mux, void *vmsg)
131 uchar *msg;
132 USED(mux);
134 msg = vmsg;
135 return msg[4];
138 static int
139 drawsettag(Mux *mux, void *vmsg, uint tag)
141 uchar *msg;
142 USED(mux);
144 msg = vmsg;
145 msg[4] = tag;
146 return 0;
149 static int
150 displayrpc(Display *d, Wsysmsg *tx, Wsysmsg *rx, void **freep)
152 int n, nn;
153 void *tpkt, *rpkt;
155 n = sizeW2M(tx);
156 tpkt = malloc(n);
157 if(freep)
158 *freep = nil;
159 if(tpkt == nil)
160 return -1;
161 tx->tag = 0;
162 if(chattydrawclient)
163 fprint(2, "<- %W\n", tx);
164 nn = convW2M(tx, tpkt, n);
165 if(nn != n){
166 free(tpkt);
167 werrstr("drawclient: sizeW2M convW2M mismatch");
168 fprint(2, "%r\n");
169 return -1;
171 /*
172 * This is the only point where we might reschedule.
173 * Muxrpc might need to acquire d->mux->lk, which could
174 * be held by some other proc (e.g., the one reading from
175 * the keyboard via Trdkbd messages). If we need to wait
176 * for the lock, don't let other threads from this proc
177 * run. This keeps up the appearance that writes to /dev/draw
178 * don't cause rescheduling. If you *do* allow rescheduling
179 * here, then flushimage(display, 1) happening in two different
180 * threads in the same proc can cause a buffer of commands
181 * to be written out twice, leading to interesting results
182 * on the screen.
184 * Threadpin and threadunpin were added to the thread library
185 * to solve exactly this problem. Be careful! They are dangerous.
187 * _pin and _unpin are aliases for threadpin and threadunpin
188 * in a threaded program and are no-ops in unthreaded programs.
189 */
190 _pin();
191 rpkt = muxrpc(d->mux, tpkt);
192 _unpin();
193 free(tpkt);
194 if(rpkt == nil){
195 werrstr("muxrpc: %r");
196 return -1;
198 GET((uchar*)rpkt, n);
199 nn = convM2W(rpkt, n, rx);
200 if(nn != n){
201 free(rpkt);
202 werrstr("drawclient: convM2W packet size mismatch %d %d %.*H", n, nn, n, rpkt);
203 fprint(2, "%r\n");
204 return -1;
206 if(chattydrawclient)
207 fprint(2, "-> %W\n", rx);
208 if(rx->type == Rerror){
209 werrstr("%s", rx->error);
210 free(rpkt);
211 return -1;
213 if(rx->type != tx->type+1){
214 werrstr("packet type mismatch -- tx %d rx %d",
215 tx->type, rx->type);
216 free(rpkt);
217 return -1;
219 if(freep)
220 *freep = rpkt;
221 else
222 free(rpkt);
223 return 0;
226 int
227 _displayinit(Display *d, char *label, char *winsize)
229 Wsysmsg tx, rx;
231 tx.type = Tinit;
232 tx.label = label;
233 tx.winsize = winsize;
234 return displayrpc(d, &tx, &rx, nil);
237 int
238 _displayrdmouse(Display *d, Mouse *m, int *resized)
240 Wsysmsg tx, rx;
242 tx.type = Trdmouse;
243 if(displayrpc(d, &tx, &rx, nil) < 0)
244 return -1;
245 *m = rx.mouse;
246 *resized = rx.resized;
247 return 0;
250 int
251 _displayrdkbd(Display *d, Rune *r)
253 Wsysmsg tx, rx;
255 tx.type = Trdkbd;
256 if(displayrpc(d, &tx, &rx, nil) < 0)
257 return -1;
258 *r = rx.rune;
259 return 0;
262 int
263 _displaymoveto(Display *d, Point p)
265 Wsysmsg tx, rx;
267 tx.type = Tmoveto;
268 tx.mouse.xy = p;
269 return displayrpc(d, &tx, &rx, nil);
272 int
273 _displaycursor(Display *d, Cursor *c)
275 Wsysmsg tx, rx;
277 tx.type = Tcursor;
278 if(c == nil){
279 memset(&tx.cursor, 0, sizeof tx.cursor);
280 tx.arrowcursor = 1;
281 }else{
282 tx.arrowcursor = 0;
283 tx.cursor = *c;
285 return displayrpc(d, &tx, &rx, nil);
288 int
289 _displaybouncemouse(Display *d, Mouse *m)
291 Wsysmsg tx, rx;
293 tx.type = Tbouncemouse;
294 tx.mouse = *m;
295 return displayrpc(d, &tx, &rx, nil);
298 int
299 _displaylabel(Display *d, char *label)
301 Wsysmsg tx, rx;
303 tx.type = Tlabel;
304 tx.label = label;
305 return displayrpc(d, &tx, &rx, nil);
308 char*
309 _displayrdsnarf(Display *d)
311 void *p;
312 char *s;
313 Wsysmsg tx, rx;
315 tx.type = Trdsnarf;
316 if(displayrpc(d, &tx, &rx, &p) < 0)
317 return nil;
318 s = strdup(rx.snarf);
319 free(p);
320 return s;
323 int
324 _displaywrsnarf(Display *d, char *snarf)
326 Wsysmsg tx, rx;
328 tx.type = Twrsnarf;
329 tx.snarf = snarf;
330 return displayrpc(d, &tx, &rx, nil);
333 int
334 _displayrddraw(Display *d, void *v, int n)
336 void *p;
337 Wsysmsg tx, rx;
339 tx.type = Trddraw;
340 tx.count = n;
341 if(displayrpc(d, &tx, &rx, &p) < 0)
342 return -1;
343 memmove(v, rx.data, rx.count);
344 free(p);
345 return rx.count;
348 int
349 _displaywrdraw(Display *d, void *v, int n)
351 Wsysmsg tx, rx;
353 tx.type = Twrdraw;
354 tx.count = n;
355 tx.data = v;
356 if(displayrpc(d, &tx, &rx, nil) < 0)
357 return -1;
358 return rx.count;
361 int
362 _displaytop(Display *d)
364 Wsysmsg tx, rx;
366 tx.type = Ttop;
367 return displayrpc(d, &tx, &rx, nil);
370 int
371 _displayresize(Display *d, Rectangle r)
373 Wsysmsg tx, rx;
375 tx.type = Tresize;
376 tx.rect = r;
377 return displayrpc(d, &tx, &rx, nil);
380 static int
381 canreadfd(int fd)
383 fd_set rs, ws, xs;
384 struct timeval tv;
386 FD_ZERO(&rs);
387 FD_ZERO(&ws);
388 FD_ZERO(&xs);
389 FD_SET(fd, &rs);
390 FD_SET(fd, &xs);
391 tv.tv_sec = 0;
392 tv.tv_usec = 0;
393 if(select(fd+1, &rs, &ws, &xs, &tv) < 0)
394 return 0;
395 if(FD_ISSET(fd, &rs) || FD_ISSET(fd, &xs))
396 return 1;
397 return 0;