Blob
1 /*2 * Window system protocol server.3 */5 #include <u.h>6 #include <errno.h>7 #include <sys/select.h>8 #include <libc.h>9 #include <thread.h>10 #include <draw.h>11 #include <memdraw.h>12 #include <memlayer.h>13 #include <keyboard.h>14 #include <mouse.h>15 #include <cursor.h>16 #include <drawfcall.h>17 #include "osx-screen.h"18 #include "devdraw.h"20 #undef time22 #define MouseMask (\23 ButtonPressMask|\24 ButtonReleaseMask|\25 PointerMotionMask|\26 Button1MotionMask|\27 Button2MotionMask|\28 Button3MotionMask)30 #define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|EnterWindowMask|LeaveWindowMask32 typedef struct Kbdbuf Kbdbuf;33 typedef struct Mousebuf Mousebuf;34 typedef struct Fdbuf Fdbuf;35 typedef struct Tagbuf Tagbuf;37 struct Kbdbuf38 {39 Rune r[32];40 int ri;41 int wi;42 int stall;43 };45 struct Mousebuf46 {47 Mouse m[32];48 Mouse last;49 int ri;50 int wi;51 int stall;52 };54 struct Tagbuf55 {56 int t[32];57 int ri;58 int wi;59 };61 Kbdbuf kbd;62 Mousebuf mouse;63 Tagbuf kbdtags;64 Tagbuf mousetags;66 void fdslide(Fdbuf*);67 void runmsg(Wsysmsg*);68 void replymsg(Wsysmsg*);69 void matchkbd(void);70 void matchmouse(void);71 int fdnoblock(int);72 Rectangle mouserect;73 int mouseresized;76 QLock lk;77 void78 zlock(void)79 {80 qlock(&lk);81 }83 void84 zunlock(void)85 {86 qunlock(&lk);87 }89 int chatty;90 int drawsleep;91 int trace;92 int multitouch = 1;94 void95 usage(void)96 {97 fprint(2, "usage: devdraw (don't run directly)\n");98 threadexitsall("usage");99 }101 void102 bell(void *v, char *msg)103 {104 if(strcmp(msg, "alarm") == 0)105 drawsleep = drawsleep ? 0 : 1000;106 noted(NCONT);107 }109 void110 threadmain(int argc, char **argv)111 {112 uchar buf[4], *mbuf;113 int nmbuf, n, nn;114 Wsysmsg m;116 /*117 * Move the protocol off stdin/stdout so that118 * any inadvertent prints don't screw things up.119 */120 dup(0, 3);121 dup(1, 4);122 close(0);123 close(1);124 open("/dev/null", OREAD);125 open("/dev/null", OWRITE);127 //trace = 1;128 fmtinstall('W', drawfcallfmt);130 ARGBEGIN{131 case 'D':132 chatty++;133 break;134 case 'M':135 multitouch = 0;136 break;137 default:138 usage();139 }ARGEND141 /*142 * Ignore arguments. They're only for good ps -a listings.143 */145 notify(bell);147 mbuf = nil;148 nmbuf = 0;149 while((n = read(3, buf, 4)) == 4){150 GET(buf, n);151 if(n > nmbuf){152 free(mbuf);153 mbuf = malloc(4+n);154 if(mbuf == nil)155 sysfatal("malloc: %r");156 nmbuf = n;157 }158 memmove(mbuf, buf, 4);159 nn = readn(3, mbuf+4, n-4);160 if(nn != n-4)161 sysfatal("eof during message");163 /* pick off messages one by one */164 if(convM2W(mbuf, nn+4, &m) <= 0)165 sysfatal("cannot convert message");166 if(trace) fprint(2, "<- %W\n", &m);167 runmsg(&m);168 }169 threadexitsall(0);170 }172 void173 replyerror(Wsysmsg *m)174 {175 char err[256];177 rerrstr(err, sizeof err);178 m->type = Rerror;179 m->error = err;180 replymsg(m);181 }183 /*184 * Handle a single wsysmsg.185 * Might queue for later (kbd, mouse read)186 */187 void188 runmsg(Wsysmsg *m)189 {190 static uchar buf[65536];191 int n;192 Memimage *i;194 switch(m->type){195 case Tinit:196 memimageinit();197 i = attachscreen(m->label, m->winsize);198 _initdisplaymemimage(i);199 replymsg(m);200 break;202 case Trdmouse:203 zlock();204 mousetags.t[mousetags.wi++] = m->tag;205 if(mousetags.wi == nelem(mousetags.t))206 mousetags.wi = 0;207 if(mousetags.wi == mousetags.ri)208 sysfatal("too many queued mouse reads");209 mouse.stall = 0;210 matchmouse();211 zunlock();212 break;214 case Trdkbd:215 zlock();216 kbdtags.t[kbdtags.wi++] = m->tag;217 if(kbdtags.wi == nelem(kbdtags.t))218 kbdtags.wi = 0;219 if(kbdtags.wi == kbdtags.ri)220 sysfatal("too many queued keyboard reads");221 kbd.stall = 0;222 matchkbd();223 zunlock();224 break;226 case Tmoveto:227 setmouse(m->mouse.xy);228 replymsg(m);229 break;231 case Tcursor:232 if(m->arrowcursor)233 setcursor(nil);234 else235 setcursor(&m->cursor);236 replymsg(m);237 break;239 case Tbouncemouse:240 // _xbouncemouse(&m->mouse);241 replymsg(m);242 break;244 case Tlabel:245 kicklabel(m->label);246 replymsg(m);247 break;249 case Trdsnarf:250 m->snarf = getsnarf();251 replymsg(m);252 free(m->snarf);253 break;255 case Twrsnarf:256 putsnarf(m->snarf);257 replymsg(m);258 break;260 case Trddraw:261 n = m->count;262 if(n > sizeof buf)263 n = sizeof buf;264 n = _drawmsgread(buf, n);265 if(n < 0)266 replyerror(m);267 else{268 m->count = n;269 m->data = buf;270 replymsg(m);271 }272 break;274 case Twrdraw:275 if(_drawmsgwrite(m->data, m->count) < 0)276 replyerror(m);277 else278 replymsg(m);279 break;281 case Ttop:282 // _xtopwindow();283 replymsg(m);284 break;286 case Tresize:287 // _xresizewindow(m->rect);288 replymsg(m);289 break;290 }291 }293 /*294 * Reply to m.295 */296 QLock replylock;297 void298 replymsg(Wsysmsg *m)299 {300 int n;301 static uchar *mbuf;302 static int nmbuf;304 /* T -> R msg */305 if(m->type%2 == 0)306 m->type++;308 if(trace) fprint(2, "-> %W\n", m);309 /* copy to output buffer */310 n = sizeW2M(m);312 qlock(&replylock);313 if(n > nmbuf){314 free(mbuf);315 mbuf = malloc(n);316 if(mbuf == nil)317 sysfatal("out of memory");318 nmbuf = n;319 }320 convW2M(m, mbuf, n);321 if(write(4, mbuf, n) != n)322 sysfatal("write: %r");323 qunlock(&replylock);324 }326 /*327 * Match queued kbd reads with queued kbd characters.328 */329 void330 matchkbd(void)331 {332 Wsysmsg m;334 if(kbd.stall)335 return;336 while(kbd.ri != kbd.wi && kbdtags.ri != kbdtags.wi){337 m.type = Rrdkbd;338 m.tag = kbdtags.t[kbdtags.ri++];339 if(kbdtags.ri == nelem(kbdtags.t))340 kbdtags.ri = 0;341 m.rune = kbd.r[kbd.ri++];342 if(kbd.ri == nelem(kbd.r))343 kbd.ri = 0;344 replymsg(&m);345 }346 }348 /*349 * Match queued mouse reads with queued mouse events.350 */351 void352 matchmouse(void)353 {354 Wsysmsg m;356 while(mouse.ri != mouse.wi && mousetags.ri != mousetags.wi){357 m.type = Rrdmouse;358 m.tag = mousetags.t[mousetags.ri++];359 if(mousetags.ri == nelem(mousetags.t))360 mousetags.ri = 0;361 m.mouse = mouse.m[mouse.ri];362 m.resized = mouseresized;363 /*364 if(m.resized)365 fprint(2, "sending resize\n");366 */367 mouseresized = 0;368 mouse.ri++;369 if(mouse.ri == nelem(mouse.m))370 mouse.ri = 0;371 replymsg(&m);372 }373 }375 void376 mousetrack(int x, int y, int b, int ms)377 {378 Mouse *m;380 if(x < mouserect.min.x)381 x = mouserect.min.x;382 if(x > mouserect.max.x)383 x = mouserect.max.x;384 if(y < mouserect.min.y)385 y = mouserect.min.y;386 if(y > mouserect.max.y)387 y = mouserect.max.y;389 zlock();390 // If reader has stopped reading, don't bother.391 // If reader is completely caught up, definitely queue.392 // Otherwise, queue only button change events.393 if(!mouse.stall)394 if(mouse.wi == mouse.ri || mouse.last.buttons != b){395 m = &mouse.last;396 m->xy.x = x;397 m->xy.y = y;398 m->buttons = b;399 m->msec = ms;401 mouse.m[mouse.wi] = *m;402 if(++mouse.wi == nelem(mouse.m))403 mouse.wi = 0;404 if(mouse.wi == mouse.ri){405 mouse.stall = 1;406 mouse.ri = 0;407 mouse.wi = 1;408 mouse.m[0] = *m;409 }410 matchmouse();411 }412 zunlock();413 }415 void416 kputc(int c)417 {418 zlock();419 kbd.r[kbd.wi++] = c;420 if(kbd.wi == nelem(kbd.r))421 kbd.wi = 0;422 if(kbd.ri == kbd.wi)423 kbd.stall = 1;424 matchkbd();425 zunlock();426 }428 void429 keystroke(int c)430 {431 static Rune k[10];432 static int alting, nk;433 int i;435 if(c == Kalt){436 alting = !alting;437 return;438 }439 if(!alting){440 kputc(c);441 return;442 }443 if(nk >= nelem(k)) // should not happen444 nk = 0;445 k[nk++] = c;446 c = _latin1(k, nk);447 if(c > 0){448 alting = 0;449 kputc(c);450 nk = 0;451 return;452 }453 if(c == -1){454 alting = 0;455 for(i=0; i<nk; i++)456 kputc(k[i]);457 nk = 0;458 return;459 }460 // need more input461 return;462 }