2 * Window system protocol server.
14 #include <drawfcall.h>
17 static void runmsg(Client*, Wsysmsg*);
18 static void replymsg(Client*, Wsysmsg*);
19 static void matchkbd(Client*);
20 static void matchmouse(Client*);
21 static void serveproc(void*);
22 static void listenproc(void*);
33 fprint(2, "usage: devdraw (don't run directly)\n");
34 threadexitsall("usage");
38 threadmain(int argc, char **argv)
43 case 'D': /* for good ps -a listings */
45 case 'f': /* fall through for backward compatibility */
50 // TODO: Update usage, man page.
51 srvname = EARGF(usage());
58 fmtinstall('H', encodefmt);
59 if((p = getenv("DEVDRAWTRACE")) != nil)
63 client0 = mallocz(sizeof(Client), 1);
65 fprint(2, "initdraw: allocating client0: out of memory");
68 client0->displaydpi = 100;
73 * Move the protocol off stdin/stdout so that
74 * any inadvertent prints don't screw things up.
80 open("/dev/null", OREAD);
81 open("/dev/null", OWRITE);
84 fmtinstall('W', drawfcallfmt);
94 // Legacy mode: serving single client on pipes.
95 proccreate(serveproc, client0, 0);
100 if((ns = getns()) == nil)
101 sysfatal("out of memory");
103 addr = smprint("unix!%s/%s", ns, srvname);
106 sysfatal("out of memory");
108 if((afd = announce(addr, adir)) < 0)
109 sysfatal("announce %s: %r", addr);
111 proccreate(listenproc, nil, 0);
124 fd = listen(adir, dir);
126 sysfatal("listen: %r");
127 c = mallocz(sizeof(Client), 1);
129 fprint(2, "initdraw: allocating client0: out of memory");
135 proccreate(serveproc, c, 0);
150 while((n = read(c->rfd, buf, 4)) == 4){
156 sysfatal("out of memory");
159 memmove(mbuf, buf, 4);
160 nn = readn(c->rfd, mbuf+4, n-4);
162 fprint(2, "serveproc: eof during message\n");
166 /* pick off messages one by one */
167 if(convM2W(mbuf, nn+4, &m) <= 0) {
168 fprint(2, "serveproc: cannot convert message\n");
171 if(trace) fprint(2, "%ud [%d] <- %W\n", nsec()/1000000, threadid(), &m);
182 replyerror(Client *c, Wsysmsg *m)
186 rerrstr(err, sizeof err);
193 * Handle a single wsysmsg.
194 * Might queue for later (kbd, mouse read)
197 runmsg(Client *c, Wsysmsg *m)
199 static uchar buf[65536];
205 c->wsysid = strdup(m->id);
210 i = rpc_attach(c, m->label, m->winsize);
215 draw_initdisplaymemimage(c, i);
221 if((c->mousetags.wi+1)%nelem(c->mousetags.t) == c->mousetags.ri) {
222 qunlock(&c->eventlk);
223 werrstr("too many queued mouse reads");
227 c->mousetags.t[c->mousetags.wi++] = m->tag;
228 if(c->mousetags.wi == nelem(c->mousetags.t))
232 qunlock(&c->eventlk);
238 if((c->kbdtags.wi+1)%nelem(c->kbdtags.t) == c->kbdtags.ri) {
239 qunlock(&c->eventlk);
240 werrstr("too many queued keyboard reads");
244 c->kbdtags.t[c->kbdtags.wi++] = (m->tag<<1) | (m->type==Trdkbd4);
245 if(c->kbdtags.wi == nelem(c->kbdtags.t))
249 qunlock(&c->eventlk);
253 c->impl->rpc_setmouse(c, m->mouse.xy);
259 c->impl->rpc_setcursor(c, nil, nil);
261 scalecursor(&m->cursor2, &m->cursor);
262 c->impl->rpc_setcursor(c, &m->cursor, &m->cursor2);
269 c->impl->rpc_setcursor(c, nil, nil);
271 c->impl->rpc_setcursor(c, &m->cursor, &m->cursor2);
276 c->impl->rpc_bouncemouse(c, m->mouse);
281 c->impl->rpc_setlabel(c, m->label);
286 m->snarf = rpc_getsnarf();
292 rpc_putsnarf(m->snarf);
300 n = draw_dataread(c, buf, n);
311 if(draw_datawrite(c, m->data, m->count) < 0)
318 c->impl->rpc_topwin(c);
323 c->impl->rpc_resizewindow(c, m->rect);
333 replymsg(Client *c, Wsysmsg *m)
341 if(trace) fprint(2, "%ud [%d] -> %W\n", nsec()/1000000, threadid(), m);
342 /* copy to output buffer */
350 sysfatal("out of memory");
353 convW2M(m, c->mbuf, n);
354 if(write(c->wfd, c->mbuf, n) != n)
355 fprint(2, "client write: %r\n");
360 * Match queued kbd reads with queued kbd characters.
370 while(c->kbd.ri != c->kbd.wi && c->kbdtags.ri != c->kbdtags.wi){
371 tag = c->kbdtags.t[c->kbdtags.ri++];
376 if(c->kbdtags.ri == nelem(c->kbdtags.t))
378 m.rune = c->kbd.r[c->kbd.ri++];
379 if(c->kbd.ri == nelem(c->kbd.r))
385 // matchmouse matches queued mouse reads with queued mouse events.
386 // It must be called with c->eventlk held.
388 matchmouse(Client *c)
392 if(canqlock(&c->eventlk)) {
393 fprint(2, "misuse of matchmouse\n");
397 while(c->mouse.ri != c->mouse.wi && c->mousetags.ri != c->mousetags.wi){
399 m.tag = c->mousetags.t[c->mousetags.ri++];
400 if(c->mousetags.ri == nelem(c->mousetags.t))
402 m.mouse = c->mouse.m[c->mouse.ri];
403 m.resized = c->mouse.resized;
404 c->mouse.resized = 0;
407 fprint(2, "sending resize\n");
410 if(c->mouse.ri == nelem(c->mouse.m))
417 gfx_mouseresized(Client *c)
419 gfx_mousetrack(c, -1, -1, -1, -1);
423 gfx_mousetrack(Client *c, int x, int y, int b, uint ms)
428 if(x == -1 && y == -1 && b == -1 && ms == -1) {
430 // repeat last mouse event for resize
432 copy = &c->mouse.m[nelem(c->mouse.m)-1];
434 copy = &c->mouse.m[c->mouse.ri-1];
439 c->mouse.resized = 1;
441 if(x < c->mouserect.min.x)
442 x = c->mouserect.min.x;
443 if(x > c->mouserect.max.x)
444 x = c->mouserect.max.x;
445 if(y < c->mouserect.min.y)
446 y = c->mouserect.min.y;
447 if(y > c->mouserect.max.y)
448 y = c->mouserect.max.y;
450 // If reader has stopped reading, don't bother.
451 // If reader is completely caught up, definitely queue.
452 // Otherwise, queue only button change events.
454 if(c->mouse.wi == c->mouse.ri || c->mouse.last.buttons != b){
461 c->mouse.m[c->mouse.wi] = *m;
462 if(++c->mouse.wi == nelem(c->mouse.m))
464 if(c->mouse.wi == c->mouse.ri){
472 qunlock(&c->eventlk);
475 // kputc adds ch to the keyboard buffer.
476 // It must be called with c->eventlk held.
478 kputc(Client *c, int ch)
480 if(canqlock(&c->eventlk)) {
481 fprint(2, "misuse of kputc\n");
485 c->kbd.r[c->kbd.wi++] = ch;
486 if(c->kbd.wi == nelem(c->kbd.r))
488 if(c->kbd.ri == c->kbd.wi)
493 // gfx_abortcompose stops any pending compose sequence,
494 // because a mouse button has been clicked.
495 // It is called from the graphics thread with no locks held.
497 gfx_abortcompose(Client *c)
504 qunlock(&c->eventlk);
507 // gfx_keystroke records a single-rune keystroke.
508 // It is called from the graphics thread with no locks held.
510 gfx_keystroke(Client *c, int ch)
516 c->kbd.alting = !c->kbd.alting;
518 qunlock(&c->eventlk);
524 else if(c->displaydpi >= 200)
528 qunlock(&c->eventlk);
529 c->impl->rpc_resizeimg(c);
534 qunlock(&c->eventlk);
537 if(c->kbd.nk >= nelem(c->kbd.k)) // should not happen
539 c->kbd.k[c->kbd.nk++] = ch;
540 ch = latin1(c->kbd.k, c->kbd.nk);
545 qunlock(&c->eventlk);
550 for(i=0; i<c->kbd.nk; i++)
551 kputc(c, c->kbd.k[i]);
553 qunlock(&c->eventlk);
557 qunlock(&c->eventlk);