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 extern Mouse _drawmouse;
13 int chattydrawclient = 0;
15 static int drawgettag(Mux *mux, void *vmsg);
16 static void* drawrecv(Mux *mux);
17 static int drawnbrecv(Mux *mux, void**);
18 static int drawsend(Mux *mux, void *vmsg);
19 static int drawsettag(Mux *mux, void *vmsg, uint tag);
20 static int canreadfd(int);
22 int
23 _displayconnect(Display *d)
24 {
25 int pid, p[2], fd, nbuf, n;
26 char *wsysid, *ns, *addr, *id;
27 uchar *buf;
28 Wsysmsg w;
30 fmtinstall('W', drawfcallfmt);
31 fmtinstall('H', encodefmt);
33 wsysid = getenv("wsysid");
34 if(wsysid != nil) {
35 // Connect to running devdraw service.
36 // wsysid=devdrawname/id
37 id = strchr(wsysid, '/');
38 if(id == nil) {
39 werrstr("invalid $wsysid");
40 return -1;
41 }
42 *id++ = '\0';
43 if((ns = getns()) == nil)
44 return -1;
45 addr = smprint("unix!%s/%s", ns, wsysid);
46 free(ns);
47 if(addr == nil)
48 return -1;
49 fd = dial(addr, 0, 0, 0);
50 free(addr);
51 if(fd < 0)
52 return -1;
53 nbuf = strlen(id) + 500;
54 buf = malloc(nbuf);
55 if(buf == nil) {
56 close(fd);
57 return -1;
58 }
59 memset(&w, 0, sizeof w);
60 w.type = Tctxt;
61 w.id = id;
62 n = convW2M(&w, buf, nbuf);
63 if(write(fd, buf, n) != n) {
64 close(fd);
65 werrstr("wsys short write: %r");
66 return -1;
67 }
68 n = readwsysmsg(fd, buf, nbuf);
69 if(n < 0) {
70 close(fd);
71 werrstr("wsys short read: %r");
72 return -1;
73 }
74 if(convM2W(buf, n, &w) <= 0) {
75 close(fd);
76 werrstr("wsys decode error");
77 return -1;
78 }
79 if(w.type != Rctxt) {
80 close(fd);
81 if(w.type == Rerror)
82 werrstr("%s", w.error);
83 else
84 werrstr("wsys rpc phase error (%d)", w.type);
85 return -1;
86 }
87 d->srvfd = fd;
88 return 0;
89 }
91 if(pipe(p) < 0)
92 return -1;
93 if((pid=fork()) < 0){
94 close(p[0]);
95 close(p[1]);
96 return -1;
97 }
98 if(pid == 0){
99 char *devdraw;
101 devdraw = getenv("DEVDRAW");
102 if(devdraw == nil)
103 devdraw = "devdraw";
104 close(p[0]);
105 dup(p[1], 0);
106 dup(p[1], 1);
107 /* execl("strace", "strace", "-o", "drawsrv.out", "drawsrv", nil); */
108 /*
109 * The argv0 has no meaning to devdraw.
110 * Pass it along only so that the various
111 * devdraws in psu -a can be distinguished.
112 * The NOLIBTHREADDAEMONIZE keeps devdraw from
113 * forking before threadmain. OS X hates it when
114 * guis fork.
116 * If client didn't use ARGBEGIN, argv0 == nil.
117 * Can't send nil through because OS X expects
118 * argv[0] to be non-nil. Also, OS X apparently
119 * expects argv[0] to be a valid executable name,
120 * so "(argv0)" is not okay. Use "devdraw"
121 * instead.
122 */
123 putenv("NOLIBTHREADDAEMONIZE", "1");
124 devdraw = getenv("DEVDRAW");
125 if(devdraw == nil)
126 devdraw = "devdraw";
127 if(argv0 == nil)
128 argv0 = devdraw;
129 execl(devdraw, argv0, argv0, "(devdraw)", nil);
130 sysfatal("exec devdraw: %r");
132 close(p[1]);
133 d->srvfd = p[0];
134 return 0;
137 int
138 _displaymux(Display *d)
140 if((d->mux = mallocz(sizeof(*d->mux), 1)) == nil)
141 return -1;
143 d->mux->mintag = 1;
144 d->mux->maxtag = 255;
145 d->mux->send = drawsend;
146 d->mux->recv = drawrecv;
147 d->mux->nbrecv = drawnbrecv;
148 d->mux->gettag = drawgettag;
149 d->mux->settag = drawsettag;
150 d->mux->aux = d;
151 muxinit(d->mux);
153 return 0;
156 static int
157 drawsend(Mux *mux, void *vmsg)
159 int n;
160 uchar *msg;
161 Display *d;
163 msg = vmsg;
164 GET(msg, n);
165 d = mux->aux;
166 return write(d->srvfd, msg, n);
169 static int
170 _drawrecv(Mux *mux, int canblock, void **vp)
172 int n;
173 uchar buf[4], *p;
174 Display *d;
176 d = mux->aux;
177 *vp = nil;
178 if(!canblock && !canreadfd(d->srvfd))
179 return 0;
180 if((n=readn(d->srvfd, buf, 4)) != 4)
181 return 1;
182 GET(buf, n);
183 p = malloc(n);
184 if(p == nil){
185 fprint(2, "out of memory allocating %d in drawrecv\n", n);
186 return 1;
188 memmove(p, buf, 4);
189 if(readn(d->srvfd, p+4, n-4) != n-4){
190 free(p);
191 return 1;
193 *vp = p;
194 return 1;
197 static void*
198 drawrecv(Mux *mux)
200 void *p;
201 _drawrecv(mux, 1, &p);
202 return p;
205 static int
206 drawnbrecv(Mux *mux, void **vp)
208 return _drawrecv(mux, 0, vp);
211 static int
212 drawgettag(Mux *mux, void *vmsg)
214 uchar *msg;
215 USED(mux);
217 msg = vmsg;
218 return msg[4];
221 static int
222 drawsettag(Mux *mux, void *vmsg, uint tag)
224 uchar *msg;
225 USED(mux);
227 msg = vmsg;
228 msg[4] = tag;
229 return 0;
232 static int
233 displayrpc(Display *d, Wsysmsg *tx, Wsysmsg *rx, void **freep)
235 int n, nn;
236 void *tpkt, *rpkt;
238 n = sizeW2M(tx);
239 tpkt = malloc(n);
240 if(freep)
241 *freep = nil;
242 if(tpkt == nil)
243 return -1;
244 tx->tag = 0;
245 if(chattydrawclient)
246 fprint(2, "<- %W\n", tx);
247 nn = convW2M(tx, tpkt, n);
248 if(nn != n){
249 free(tpkt);
250 werrstr("drawclient: sizeW2M convW2M mismatch");
251 fprint(2, "%r\n");
252 return -1;
254 /*
255 * This is the only point where we might reschedule.
256 * Muxrpc might need to acquire d->mux->lk, which could
257 * be held by some other proc (e.g., the one reading from
258 * the keyboard via Trdkbd messages). If we need to wait
259 * for the lock, don't let other threads from this proc
260 * run. This keeps up the appearance that writes to /dev/draw
261 * don't cause rescheduling. If you *do* allow rescheduling
262 * here, then flushimage(display, 1) happening in two different
263 * threads in the same proc can cause a buffer of commands
264 * to be written out twice, leading to interesting results
265 * on the screen.
267 * Threadpin and threadunpin were added to the thread library
268 * to solve exactly this problem. Be careful! They are dangerous.
270 * _pin and _unpin are aliases for threadpin and threadunpin
271 * in a threaded program and are no-ops in unthreaded programs.
272 */
273 _pin();
274 rpkt = muxrpc(d->mux, tpkt);
275 _unpin();
276 free(tpkt);
277 if(rpkt == nil){
278 werrstr("muxrpc: %r");
279 return -1;
281 GET((uchar*)rpkt, n);
282 nn = convM2W(rpkt, n, rx);
283 if(nn != n){
284 free(rpkt);
285 werrstr("drawclient: convM2W packet size mismatch %d %d %.*H", n, nn, n, rpkt);
286 fprint(2, "%r\n");
287 return -1;
289 if(chattydrawclient)
290 fprint(2, "-> %W\n", rx);
291 if(rx->type == Rerror){
292 werrstr("%s", rx->error);
293 free(rpkt);
294 return -1;
296 if(rx->type != tx->type+1){
297 werrstr("packet type mismatch -- tx %d rx %d",
298 tx->type, rx->type);
299 free(rpkt);
300 return -1;
302 if(freep)
303 *freep = rpkt;
304 else
305 free(rpkt);
306 return 0;
309 int
310 _displayinit(Display *d, char *label, char *winsize)
312 Wsysmsg tx, rx;
314 tx.type = Tinit;
315 tx.label = label;
316 tx.winsize = winsize;
317 return displayrpc(d, &tx, &rx, nil);
320 int
321 _displayrdmouse(Display *d, Mouse *m, int *resized)
323 Wsysmsg tx, rx;
325 tx.type = Trdmouse;
326 if(displayrpc(d, &tx, &rx, nil) < 0)
327 return -1;
328 _drawmouse = rx.mouse;
329 *m = rx.mouse;
330 *resized = rx.resized;
331 return 0;
334 int
335 _displayrdkbd(Display *d, Rune *r)
337 Wsysmsg tx, rx;
339 tx.type = Trdkbd4;
340 if(displayrpc(d, &tx, &rx, nil) < 0)
341 return -1;
342 *r = rx.rune;
343 return 0;
346 int
347 _displaymoveto(Display *d, Point p)
349 Wsysmsg tx, rx;
351 tx.type = Tmoveto;
352 tx.mouse.xy = p;
353 if(displayrpc(d, &tx, &rx, nil) < 0)
354 return -1;
355 _drawmouse.xy = p;
356 return flushimage(d, 1);
359 int
360 _displaycursor(Display *d, Cursor *c, Cursor2 *c2)
362 Wsysmsg tx, rx;
364 tx.type = Tcursor2;
365 if(c == nil){
366 memset(&tx.cursor, 0, sizeof tx.cursor);
367 memset(&tx.cursor2, 0, sizeof tx.cursor2);
368 tx.arrowcursor = 1;
369 }else{
370 tx.arrowcursor = 0;
371 tx.cursor = *c;
372 if(c2 != nil)
373 tx.cursor2 = *c2;
374 else
375 scalecursor(&tx.cursor2, c);
377 return displayrpc(d, &tx, &rx, nil);
380 int
381 _displaybouncemouse(Display *d, Mouse *m)
383 Wsysmsg tx, rx;
385 tx.type = Tbouncemouse;
386 tx.mouse = *m;
387 return displayrpc(d, &tx, &rx, nil);
390 int
391 _displaylabel(Display *d, char *label)
393 Wsysmsg tx, rx;
395 tx.type = Tlabel;
396 tx.label = label;
397 return displayrpc(d, &tx, &rx, nil);
400 char*
401 _displayrdsnarf(Display *d)
403 void *p;
404 char *s;
405 Wsysmsg tx, rx;
407 tx.type = Trdsnarf;
408 if(displayrpc(d, &tx, &rx, &p) < 0)
409 return nil;
410 s = strdup(rx.snarf);
411 free(p);
412 return s;
415 int
416 _displaywrsnarf(Display *d, char *snarf)
418 Wsysmsg tx, rx;
420 tx.type = Twrsnarf;
421 tx.snarf = snarf;
422 return displayrpc(d, &tx, &rx, nil);
425 int
426 _displayrddraw(Display *d, void *v, int n)
428 void *p;
429 Wsysmsg tx, rx;
431 tx.type = Trddraw;
432 tx.count = n;
433 if(displayrpc(d, &tx, &rx, &p) < 0)
434 return -1;
435 memmove(v, rx.data, rx.count);
436 free(p);
437 return rx.count;
440 int
441 _displaywrdraw(Display *d, void *v, int n)
443 Wsysmsg tx, rx;
445 tx.type = Twrdraw;
446 tx.count = n;
447 tx.data = v;
448 if(displayrpc(d, &tx, &rx, nil) < 0)
449 return -1;
450 return rx.count;
453 int
454 _displaytop(Display *d)
456 Wsysmsg tx, rx;
458 tx.type = Ttop;
459 return displayrpc(d, &tx, &rx, nil);
462 int
463 _displayresize(Display *d, Rectangle r)
465 Wsysmsg tx, rx;
467 tx.type = Tresize;
468 tx.rect = r;
469 return displayrpc(d, &tx, &rx, nil);
472 static int
473 canreadfd(int fd)
475 fd_set rs, ws, xs;
476 struct timeval tv;
478 FD_ZERO(&rs);
479 FD_ZERO(&ws);
480 FD_ZERO(&xs);
481 FD_SET(fd, &rs);
482 FD_SET(fd, &xs);
483 tv.tv_sec = 0;
484 tv.tv_usec = 0;
485 if(select(fd+1, &rs, &ws, &xs, &tv) < 0)
486 return 0;
487 if(FD_ISSET(fd, &rs) || FD_ISSET(fd, &xs))
488 return 1;
489 return 0;