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 execl("devdraw", "devdraw", nil);
42 sysfatal("exec devdraw: %r");
43 }
44 close(p[1]);
45 d->srvfd = p[0];
46 return 0;
47 }
49 int
50 _displaymux(Display *d)
51 {
52 if((d->mux = mallocz(sizeof(*d->mux), 1)) == nil)
53 return -1;
55 d->mux->mintag = 1;
56 d->mux->maxtag = 255;
57 d->mux->send = drawsend;
58 d->mux->recv = drawrecv;
59 d->mux->nbrecv = drawnbrecv;
60 d->mux->gettag = drawgettag;
61 d->mux->settag = drawsettag;
62 d->mux->aux = d;
63 muxinit(d->mux);
65 return 0;
66 }
68 static int
69 drawsend(Mux *mux, void *vmsg)
70 {
71 int n;
72 uchar *msg;
73 Display *d;
75 msg = vmsg;
76 GET(msg, n);
77 d = mux->aux;
78 return write(d->srvfd, msg, n);
79 }
81 static void*
82 _drawrecv(Mux *mux, int nb)
83 {
84 int n;
85 uchar buf[4], *p;
86 Display *d;
88 d = mux->aux;
89 if(nb && !canreadfd(d->srvfd))
90 return nil;
91 if((n=readn(d->srvfd, buf, 4)) != 4)
92 return nil;
93 GET(buf, n);
94 p = malloc(n);
95 if(p == nil){
96 fprint(2, "out of memory allocating %d in drawrecv\n", n);
97 return nil;
98 }
99 memmove(p, buf, 4);
100 if(readn(d->srvfd, p+4, n-4) != n-4)
101 return nil;
102 return p;
105 static void*
106 drawrecv(Mux *mux)
108 return _drawrecv(mux, 0);
111 static void*
112 drawnbrecv(Mux *mux)
114 return _drawrecv(mux, 1);
117 static int
118 drawgettag(Mux *mux, void *vmsg)
120 USED(mux);
121 uchar *msg;
123 msg = vmsg;
124 return msg[4];
127 static int
128 drawsettag(Mux *mux, void *vmsg, uint tag)
130 USED(mux);
131 uchar *msg;
133 msg = vmsg;
134 msg[4] = tag;
135 return 0;
138 static int
139 displayrpc(Display *d, Wsysmsg *tx, Wsysmsg *rx, void **freep)
141 int n, nn;
142 void *tpkt, *rpkt;
144 n = sizeW2M(tx);
145 tpkt = malloc(n);
146 if(freep)
147 *freep = nil;
148 if(tpkt == nil)
149 return -1;
150 tx->tag = 0;
151 if(chattydrawclient)
152 fprint(2, "<- %W\n", tx);
153 nn = convW2M(tx, tpkt, n);
154 if(nn != n){
155 free(tpkt);
156 werrstr("drawclient: sizeW2M convW2M mismatch");
157 fprint(2, "%r\n");
158 return -1;
160 rpkt = muxrpc(d->mux, tpkt);
161 free(tpkt);
162 if(rpkt == nil){
163 werrstr("muxrpc: %r");
164 return -1;
166 GET((uchar*)rpkt, n);
167 nn = convM2W(rpkt, n, rx);
168 if(nn != n){
169 free(rpkt);
170 werrstr("drawclient: convM2W packet size mismatch %d %d %.*H", n, nn, n, rpkt);
171 fprint(2, "%r\n");
172 return -1;
174 if(chattydrawclient)
175 fprint(2, "-> %W\n", rx);
176 if(rx->type == Rerror){
177 werrstr("%s", rx->error);
178 free(rpkt);
179 return -1;
181 if(rx->type != tx->type+1){
182 werrstr("packet type mismatch -- tx %d rx %d",
183 tx->type, rx->type);
184 free(rpkt);
185 return -1;
187 if(freep)
188 *freep = rpkt;
189 else
190 free(rpkt);
191 return 0;
194 int
195 _displayinit(Display *d, char *label, char *winsize)
197 Wsysmsg tx, rx;
199 tx.type = Tinit;
200 tx.label = label;
201 tx.winsize = winsize;
202 return displayrpc(d, &tx, &rx, nil);
205 int
206 _displayrdmouse(Display *d, Mouse *m, int *resized)
208 Wsysmsg tx, rx;
210 tx.type = Trdmouse;
211 if(displayrpc(d, &tx, &rx, nil) < 0)
212 return -1;
213 *m = rx.mouse;
214 *resized = rx.resized;
215 return 0;
218 int
219 _displayrdkbd(Display *d, Rune *r)
221 Wsysmsg tx, rx;
223 tx.type = Trdkbd;
224 if(displayrpc(d, &tx, &rx, nil) < 0)
225 return -1;
226 *r = rx.rune;
227 return 0;
230 int
231 _displaymoveto(Display *d, Point p)
233 Wsysmsg tx, rx;
235 tx.type = Tmoveto;
236 tx.mouse.xy = p;
237 return displayrpc(d, &tx, &rx, nil);
240 int
241 _displaycursor(Display *d, Cursor *c)
243 Wsysmsg tx, rx;
245 tx.type = Tcursor;
246 if(c == nil){
247 memset(&tx.cursor, 0, sizeof tx.cursor);
248 tx.arrowcursor = 1;
249 }else{
250 tx.arrowcursor = 0;
251 tx.cursor = *c;
253 return displayrpc(d, &tx, &rx, nil);
256 int
257 _displaybouncemouse(Display *d, Mouse *m)
259 Wsysmsg tx, rx;
261 tx.type = Tbouncemouse;
262 tx.mouse = *m;
263 return displayrpc(d, &tx, &rx, nil);
266 int
267 _displaylabel(Display *d, char *label)
269 Wsysmsg tx, rx;
271 tx.type = Tlabel;
272 tx.label = label;
273 return displayrpc(d, &tx, &rx, nil);
276 char*
277 _displayrdsnarf(Display *d)
279 void *p;
280 char *s;
281 Wsysmsg tx, rx;
283 tx.type = Trdsnarf;
284 if(displayrpc(d, &tx, &rx, &p) < 0)
285 return nil;
286 s = strdup(rx.snarf);
287 free(p);
288 return s;
291 int
292 _displaywrsnarf(Display *d, char *snarf)
294 Wsysmsg tx, rx;
296 tx.type = Twrsnarf;
297 tx.snarf = snarf;
298 return displayrpc(d, &tx, &rx, nil);
301 int
302 _displayrddraw(Display *d, void *v, int n)
304 void *p;
305 Wsysmsg tx, rx;
307 tx.type = Trddraw;
308 tx.count = n;
309 if(displayrpc(d, &tx, &rx, &p) < 0)
310 return -1;
311 memmove(v, rx.data, rx.count);
312 free(p);
313 return rx.count;
316 int
317 _displaywrdraw(Display *d, void *v, int n)
319 Wsysmsg tx, rx;
321 tx.type = Twrdraw;
322 tx.count = n;
323 tx.data = v;
324 if(displayrpc(d, &tx, &rx, nil) < 0)
325 return -1;
326 return rx.count;
329 int
330 _displaytop(Display *d)
332 Wsysmsg tx, rx;
334 tx.type = Ttop;
335 return displayrpc(d, &tx, &rx, nil);
338 int
339 _displayresize(Display *d, Rectangle r)
341 Wsysmsg tx, rx;
343 tx.type = Tresize;
344 tx.rect = r;
345 return displayrpc(d, &tx, &rx, nil);
348 static int
349 canreadfd(int fd)
351 fd_set rs, ws, xs;
352 struct timeval tv;
354 FD_ZERO(&rs);
355 FD_ZERO(&ws);
356 FD_ZERO(&xs);
357 FD_SET(fd, &rs);
358 FD_SET(fd, &xs);
359 tv.tv_sec = 0;
360 tv.tv_usec = 0;
361 if(select(fd+1, &rs, &ws, &xs, &tv) < 0)
362 return 0;
363 if(FD_ISSET(fd, &rs) || FD_ISSET(fd, &xs))
364 return 1;
365 return 0;