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 void* drawnbrecv(Mux *mux);
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 void*
87 _drawrecv(Mux *mux, int nb)
88 {
89 int n;
90 uchar buf[4], *p;
91 Display *d;
93 d = mux->aux;
94 if(nb && !canreadfd(d->srvfd))
95 return nil;
96 if((n=readn(d->srvfd, buf, 4)) != 4)
97 return nil;
98 GET(buf, n);
99 p = malloc(n);
100 if(p == nil){
101 fprint(2, "out of memory allocating %d in drawrecv\n", n);
102 return nil;
104 memmove(p, buf, 4);
105 if(readn(d->srvfd, p+4, n-4) != n-4)
106 return nil;
107 return p;
110 static void*
111 drawrecv(Mux *mux)
113 return _drawrecv(mux, 0);
116 static void*
117 drawnbrecv(Mux *mux)
119 return _drawrecv(mux, 1);
122 static int
123 drawgettag(Mux *mux, void *vmsg)
125 uchar *msg;
126 USED(mux);
128 msg = vmsg;
129 return msg[4];
132 static int
133 drawsettag(Mux *mux, void *vmsg, uint tag)
135 uchar *msg;
136 USED(mux);
138 msg = vmsg;
139 msg[4] = tag;
140 return 0;
143 static int
144 displayrpc(Display *d, Wsysmsg *tx, Wsysmsg *rx, void **freep)
146 int n, nn;
147 void *tpkt, *rpkt;
149 n = sizeW2M(tx);
150 tpkt = malloc(n);
151 if(freep)
152 *freep = nil;
153 if(tpkt == nil)
154 return -1;
155 tx->tag = 0;
156 if(chattydrawclient)
157 fprint(2, "<- %W\n", tx);
158 nn = convW2M(tx, tpkt, n);
159 if(nn != n){
160 free(tpkt);
161 werrstr("drawclient: sizeW2M convW2M mismatch");
162 fprint(2, "%r\n");
163 return -1;
165 /*
166 * This is the only point where we might reschedule.
167 * Muxrpc might need to acquire d->mux->lk, which could
168 * be held by some other proc (e.g., the one reading from
169 * the keyboard via Trdkbd messages). If we need to wait
170 * for the lock, don't let other threads from this proc
171 * run. This keeps up the appearance that writes to /dev/draw
172 * don't cause rescheduling. If you *do* allow rescheduling
173 * here, then flushimage(display, 1) happening in two different
174 * threads in the same proc can cause a buffer of commands
175 * to be written out twice, leading to interesting results
176 * on the screen.
178 * Threadpin and threadunpin were added to the thread library
179 * to solve exactly this problem. Be careful! They are dangerous.
181 * _pin and _unpin are aliases for threadpin and threadunpin
182 * in a threaded program and are no-ops in unthreaded programs.
183 */
184 _pin();
185 rpkt = muxrpc(d->mux, tpkt);
186 _unpin();
187 free(tpkt);
188 if(rpkt == nil){
189 werrstr("muxrpc: %r");
190 return -1;
192 GET((uchar*)rpkt, n);
193 nn = convM2W(rpkt, n, rx);
194 if(nn != n){
195 free(rpkt);
196 werrstr("drawclient: convM2W packet size mismatch %d %d %.*H", n, nn, n, rpkt);
197 fprint(2, "%r\n");
198 return -1;
200 if(chattydrawclient)
201 fprint(2, "-> %W\n", rx);
202 if(rx->type == Rerror){
203 werrstr("%s", rx->error);
204 free(rpkt);
205 return -1;
207 if(rx->type != tx->type+1){
208 werrstr("packet type mismatch -- tx %d rx %d",
209 tx->type, rx->type);
210 free(rpkt);
211 return -1;
213 if(freep)
214 *freep = rpkt;
215 else
216 free(rpkt);
217 return 0;
220 int
221 _displayinit(Display *d, char *label, char *winsize)
223 Wsysmsg tx, rx;
225 tx.type = Tinit;
226 tx.label = label;
227 tx.winsize = winsize;
228 return displayrpc(d, &tx, &rx, nil);
231 int
232 _displayrdmouse(Display *d, Mouse *m, int *resized)
234 Wsysmsg tx, rx;
236 tx.type = Trdmouse;
237 if(displayrpc(d, &tx, &rx, nil) < 0)
238 return -1;
239 *m = rx.mouse;
240 *resized = rx.resized;
241 return 0;
244 int
245 _displayrdkbd(Display *d, Rune *r)
247 Wsysmsg tx, rx;
249 tx.type = Trdkbd;
250 if(displayrpc(d, &tx, &rx, nil) < 0)
251 return -1;
252 *r = rx.rune;
253 return 0;
256 int
257 _displaymoveto(Display *d, Point p)
259 Wsysmsg tx, rx;
261 tx.type = Tmoveto;
262 tx.mouse.xy = p;
263 return displayrpc(d, &tx, &rx, nil);
266 int
267 _displaycursor(Display *d, Cursor *c)
269 Wsysmsg tx, rx;
271 tx.type = Tcursor;
272 if(c == nil){
273 memset(&tx.cursor, 0, sizeof tx.cursor);
274 tx.arrowcursor = 1;
275 }else{
276 tx.arrowcursor = 0;
277 tx.cursor = *c;
279 return displayrpc(d, &tx, &rx, nil);
282 int
283 _displaybouncemouse(Display *d, Mouse *m)
285 Wsysmsg tx, rx;
287 tx.type = Tbouncemouse;
288 tx.mouse = *m;
289 return displayrpc(d, &tx, &rx, nil);
292 int
293 _displaylabel(Display *d, char *label)
295 Wsysmsg tx, rx;
297 tx.type = Tlabel;
298 tx.label = label;
299 return displayrpc(d, &tx, &rx, nil);
302 char*
303 _displayrdsnarf(Display *d)
305 void *p;
306 char *s;
307 Wsysmsg tx, rx;
309 tx.type = Trdsnarf;
310 if(displayrpc(d, &tx, &rx, &p) < 0)
311 return nil;
312 s = strdup(rx.snarf);
313 free(p);
314 return s;
317 int
318 _displaywrsnarf(Display *d, char *snarf)
320 Wsysmsg tx, rx;
322 tx.type = Twrsnarf;
323 tx.snarf = snarf;
324 return displayrpc(d, &tx, &rx, nil);
327 int
328 _displayrddraw(Display *d, void *v, int n)
330 void *p;
331 Wsysmsg tx, rx;
333 tx.type = Trddraw;
334 tx.count = n;
335 if(displayrpc(d, &tx, &rx, &p) < 0)
336 return -1;
337 memmove(v, rx.data, rx.count);
338 free(p);
339 return rx.count;
342 int
343 _displaywrdraw(Display *d, void *v, int n)
345 Wsysmsg tx, rx;
347 tx.type = Twrdraw;
348 tx.count = n;
349 tx.data = v;
350 if(displayrpc(d, &tx, &rx, nil) < 0)
351 return -1;
352 return rx.count;
355 int
356 _displaytop(Display *d)
358 Wsysmsg tx, rx;
360 tx.type = Ttop;
361 return displayrpc(d, &tx, &rx, nil);
364 int
365 _displayresize(Display *d, Rectangle r)
367 Wsysmsg tx, rx;
369 tx.type = Tresize;
370 tx.rect = r;
371 return displayrpc(d, &tx, &rx, nil);
374 static int
375 canreadfd(int fd)
377 fd_set rs, ws, xs;
378 struct timeval tv;
380 FD_ZERO(&rs);
381 FD_ZERO(&ws);
382 FD_ZERO(&xs);
383 FD_SET(fd, &rs);
384 FD_SET(fd, &xs);
385 tv.tv_sec = 0;
386 tv.tv_usec = 0;
387 if(select(fd+1, &rs, &ws, &xs, &tv) < 0)
388 return 0;
389 if(FD_ISSET(fd, &rs) || FD_ISSET(fd, &xs))
390 return 1;
391 return 0;