Blob
1 /*2 * Window system protocol server.3 */5 #include <u.h>6 #include <libc.h>7 #include "cocoa-thread.h"8 #include <draw.h>9 #include <memdraw.h>10 #include <keyboard.h>11 #include <mouse.h>12 #include <cursor.h>13 #include <drawfcall.h>14 #include "cocoa-screen.h"15 #include "devdraw.h"17 typedef struct Kbdbuf Kbdbuf;18 typedef struct Mousebuf Mousebuf;19 typedef struct Fdbuf Fdbuf;20 typedef struct Tagbuf Tagbuf;22 struct Kbdbuf23 {24 Rune r[32];25 int ri;26 int wi;27 int stall;28 };30 struct Mousebuf31 {32 Mouse m[32];33 Mouse last;34 int ri;35 int wi;36 int stall;37 };39 struct Tagbuf40 {41 int t[32];42 int ri;43 int wi;44 };46 Kbdbuf kbd;47 Mousebuf mouse;48 Tagbuf kbdtags;49 Tagbuf mousetags;51 void runmsg(Wsysmsg*);52 void replymsg(Wsysmsg*);53 void matchkbd(void);54 void matchmouse(void);57 QLock lk;58 void59 zlock(void)60 {61 qlock(&lk);62 }64 void65 zunlock(void)66 {67 qunlock(&lk);68 }70 int trace = 0;72 void73 servep9p(void)74 {75 uchar buf[4], *mbuf;76 int nmbuf, n, nn;77 Wsysmsg m;79 fmtinstall('W', drawfcallfmt);81 mbuf = nil;82 nmbuf = 0;83 while((n = read(3, buf, 4)) == 4){84 GET(buf, n);85 if(n > nmbuf){86 free(mbuf);87 mbuf = malloc(4+n);88 if(mbuf == nil)89 sysfatal("malloc: %r");90 nmbuf = n;91 }92 memmove(mbuf, buf, 4);93 nn = readn(3, mbuf+4, n-4);94 if(nn != n-4)95 sysfatal("eof during message");97 /* pick off messages one by one */98 if(convM2W(mbuf, nn+4, &m) <= 0)99 sysfatal("cannot convert message");100 if(trace) fprint(2, "<- %W\n", &m);101 runmsg(&m);102 }103 }105 void106 replyerror(Wsysmsg *m)107 {108 char err[256];110 rerrstr(err, sizeof err);111 m->type = Rerror;112 m->error = err;113 replymsg(m);114 }116 /*117 * Handle a single wsysmsg.118 * Might queue for later (kbd, mouse read)119 */120 void121 runmsg(Wsysmsg *m)122 {123 static uchar buf[65536];124 int n;125 Memimage *i;127 switch(m->type){128 case Tinit:129 memimageinit();130 i = attachscreen(m->label, m->winsize);131 _initdisplaymemimage(i);132 replymsg(m);133 break;135 case Trdmouse:136 zlock();137 mousetags.t[mousetags.wi++] = m->tag;138 if(mousetags.wi == nelem(mousetags.t))139 mousetags.wi = 0;140 if(mousetags.wi == mousetags.ri)141 sysfatal("too many queued mouse reads");142 mouse.stall = 0;143 matchmouse();144 zunlock();145 break;147 case Trdkbd:148 zlock();149 kbdtags.t[kbdtags.wi++] = m->tag;150 if(kbdtags.wi == nelem(kbdtags.t))151 kbdtags.wi = 0;152 if(kbdtags.wi == kbdtags.ri)153 sysfatal("too many queued keyboard reads");154 kbd.stall = 0;155 matchkbd();156 zunlock();157 break;159 case Tmoveto:160 setmouse(m->mouse.xy);161 replymsg(m);162 break;164 case Tcursor:165 if(m->arrowcursor)166 setcursor(nil);167 else168 setcursor(&m->cursor);169 replymsg(m);170 break;172 case Tbouncemouse:173 // _xbouncemouse(&m->mouse);174 replymsg(m);175 break;177 case Tlabel:178 kicklabel(m->label);179 replymsg(m);180 break;182 case Trdsnarf:183 m->snarf = getsnarf();184 replymsg(m);185 free(m->snarf);186 break;188 case Twrsnarf:189 putsnarf(m->snarf);190 replymsg(m);191 break;193 case Trddraw:194 n = m->count;195 if(n > sizeof buf)196 n = sizeof buf;197 n = _drawmsgread(buf, n);198 if(n < 0)199 replyerror(m);200 else{201 m->count = n;202 m->data = buf;203 replymsg(m);204 }205 break;207 case Twrdraw:208 if(_drawmsgwrite(m->data, m->count) < 0)209 replyerror(m);210 else211 replymsg(m);212 break;214 case Ttop:215 topwin();216 replymsg(m);217 break;219 case Tresize:220 // _xresizewindow(m->rect);221 replymsg(m);222 break;223 }224 }226 /*227 * Reply to m.228 */229 QLock replylock;230 void231 replymsg(Wsysmsg *m)232 {233 int n;234 static uchar *mbuf;235 static int nmbuf;237 /* T -> R msg */238 if(m->type%2 == 0)239 m->type++;241 if(trace) fprint(2, "-> %W\n", m);242 /* copy to output buffer */243 n = sizeW2M(m);245 qlock(&replylock);246 if(n > nmbuf){247 free(mbuf);248 mbuf = malloc(n);249 if(mbuf == nil)250 sysfatal("out of memory");251 nmbuf = n;252 }253 convW2M(m, mbuf, n);254 if(write(4, mbuf, n) != n)255 sysfatal("write: %r");256 qunlock(&replylock);257 }259 /*260 * Match queued kbd reads with queued kbd characters.261 */262 void263 matchkbd(void)264 {265 Wsysmsg m;267 if(kbd.stall)268 return;269 while(kbd.ri != kbd.wi && kbdtags.ri != kbdtags.wi){270 m.type = Rrdkbd;271 m.tag = kbdtags.t[kbdtags.ri++];272 if(kbdtags.ri == nelem(kbdtags.t))273 kbdtags.ri = 0;274 m.rune = kbd.r[kbd.ri++];275 if(kbd.ri == nelem(kbd.r))276 kbd.ri = 0;277 replymsg(&m);278 }279 }281 /*282 * Match queued mouse reads with queued mouse events.283 */284 void285 matchmouse(void)286 {287 Wsysmsg m;289 while(mouse.ri != mouse.wi && mousetags.ri != mousetags.wi){290 m.type = Rrdmouse;291 m.tag = mousetags.t[mousetags.ri++];292 if(mousetags.ri == nelem(mousetags.t))293 mousetags.ri = 0;294 m.mouse = mouse.m[mouse.ri];295 m.resized = mouseresized;296 /*297 if(m.resized)298 fprint(2, "sending resize\n");299 */300 mouseresized = 0;301 mouse.ri++;302 if(mouse.ri == nelem(mouse.m))303 mouse.ri = 0;304 replymsg(&m);305 }306 }308 void309 mousetrack(int x, int y, int b, uint ms)310 {311 Mouse *m;313 if(x < mouserect.min.x)314 x = mouserect.min.x;315 if(x > mouserect.max.x)316 x = mouserect.max.x;317 if(y < mouserect.min.y)318 y = mouserect.min.y;319 if(y > mouserect.max.y)320 y = mouserect.max.y;322 zlock();323 // If reader has stopped reading, don't bother.324 // If reader is completely caught up, definitely queue.325 // Otherwise, queue only button change events.326 if(!mouse.stall)327 if(mouse.wi == mouse.ri || mouse.last.buttons != b){328 m = &mouse.last;329 m->xy.x = x;330 m->xy.y = y;331 m->buttons = b;332 m->msec = ms;334 mouse.m[mouse.wi] = *m;335 if(++mouse.wi == nelem(mouse.m))336 mouse.wi = 0;337 if(mouse.wi == mouse.ri){338 mouse.stall = 1;339 mouse.ri = 0;340 mouse.wi = 1;341 mouse.m[0] = *m;342 }343 matchmouse();344 }345 zunlock();346 }348 void349 kputc(int c)350 {351 zlock();352 kbd.r[kbd.wi++] = c;353 if(kbd.wi == nelem(kbd.r))354 kbd.wi = 0;355 if(kbd.ri == kbd.wi)356 kbd.stall = 1;357 matchkbd();358 zunlock();359 }361 static int alting;363 void364 abortcompose(void)365 {366 if(alting)367 keystroke(Kalt);368 }370 void resizeimg(void);372 void373 keystroke(int c)374 {375 static Rune k[10];376 static int nk;377 int i;379 if(c == Kalt){380 alting = !alting;381 nk = 0;382 return;383 }384 if(c == Kcmd+'r') {385 if(forcedpi)386 forcedpi = 0;387 else if(displaydpi >= 200)388 forcedpi = 100;389 else390 forcedpi = 225;391 resizeimg();392 return;393 }394 if(!alting){395 kputc(c);396 return;397 }398 if(nk >= nelem(k)) // should not happen399 nk = 0;400 k[nk++] = c;401 c = _latin1(k, nk);402 if(c > 0){403 alting = 0;404 kputc(c);405 nk = 0;406 return;407 }408 if(c == -1){409 alting = 0;410 for(i=0; i<nk; i++)411 kputc(k[i]);412 nk = 0;413 return;414 }415 // need more input416 return;417 }