Blob
1 #define Point OSXPoint2 #define Rect OSXRect3 #define Cursor OSXCursor4 #import <AppKit/AppKit.h>5 #undef Rect6 #undef Point7 #undef Cursor9 /*10 * Window system protocol server.11 */13 #include <u.h>14 #include <errno.h>15 #include <sys/select.h>16 #include <libc.h>17 #include <draw.h>18 #include <memdraw.h>19 #include <memlayer.h>20 #include <keyboard.h>21 #include <mouse.h>22 #include <cursor.h>23 #include <drawfcall.h>24 #include "osx-screen.h"25 #include "devdraw.h"27 AUTOFRAMEWORK(AppKit)29 #import "osx-delegate.h"31 #undef time33 #define MouseMask (\34 ButtonPressMask|\35 ButtonReleaseMask|\36 PointerMotionMask|\37 Button1MotionMask|\38 Button2MotionMask|\39 Button3MotionMask)41 #define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|EnterWindowMask|LeaveWindowMask43 typedef struct Kbdbuf Kbdbuf;44 typedef struct Mousebuf Mousebuf;45 typedef struct Fdbuf Fdbuf;46 typedef struct Tagbuf Tagbuf;48 struct Kbdbuf49 {50 Rune r[32];51 int ri;52 int wi;53 int stall;54 };56 struct Mousebuf57 {58 Mouse m[32];59 Mouse last;60 int ri;61 int wi;62 int stall;63 };65 struct Tagbuf66 {67 int t[32];68 int ri;69 int wi;70 };72 Kbdbuf kbd;73 Mousebuf mouse;74 Tagbuf kbdtags;75 Tagbuf mousetags;77 void fdslide(Fdbuf*);78 void runmsg(Wsysmsg*);79 void replymsg(Wsysmsg*);80 void matchkbd(void);81 void matchmouse(void);82 int fdnoblock(int);83 Rectangle mouserect;84 int mouseresized;87 QLock lk;88 void89 zlock(void)90 {91 qlock(&lk);92 }94 void95 zunlock(void)96 {97 qunlock(&lk);98 }100 int chatty;101 int drawsleep;102 int trace;104 void105 usage(void)106 {107 fprint(2, "usage: devdraw (don't run directly)\n");108 exits("usage");109 }111 void112 bell(void *v, char *msg)113 {114 if(strcmp(msg, "alarm") == 0)115 drawsleep = drawsleep ? 0 : 1000;116 noted(NCONT);117 }119 int120 main(int argc, char **argv)121 {122 NSAutoreleasePool *pool = nil;123 NSApplication *application = nil;124 DevdrawDelegate *app = nil;125 /*126 * Move the protocol off stdin/stdout so that127 * any inadvertent prints don't screw things up.128 */129 dup(0, 3);130 dup(1, 4);131 close(0);132 close(1);133 open("/dev/null", OREAD);134 open("/dev/null", OWRITE);136 trace = 1;137 fmtinstall('W', drawfcallfmt);139 ARGBEGIN{140 case 'D':141 chatty++;142 break;143 default:144 usage();145 }ARGEND147 /*148 * Ignore arguments. They're only for good ps -a listings.149 */151 notify(bell);153 pool = [[NSAutoreleasePool alloc] init];154 application = [NSApplication sharedApplication];155 app = [[DevdrawDelegate alloc] init];156 [application setDelegate:app];157 [application run];158 [application setDelegate:nil];159 [app release];160 [pool release];161 return 0;162 }164 void165 replyerror(Wsysmsg *m)166 {167 char err[256];169 rerrstr(err, sizeof err);170 m->type = Rerror;171 m->error = err;172 replymsg(m);173 }175 /*176 * Handle a single wsysmsg.177 * Might queue for later (kbd, mouse read)178 */179 void180 runmsg(Wsysmsg *m)181 {182 static uchar buf[65536];183 int n;184 Memimage *i;186 switch(m->type){187 case Tinit:188 memimageinit();189 i = attachscreen(m->label, m->winsize);190 _initdisplaymemimage(i);191 replymsg(m);192 break;194 case Trdmouse:195 // zlock();196 mousetags.t[mousetags.wi++] = m->tag;197 if(mousetags.wi == nelem(mousetags.t))198 mousetags.wi = 0;199 if(mousetags.wi == mousetags.ri)200 sysfatal("too many queued mouse reads");201 mouse.stall = 0;202 matchmouse();203 // zunlock();204 break;206 case Trdkbd:207 zlock();208 kbdtags.t[kbdtags.wi++] = m->tag;209 if(kbdtags.wi == nelem(kbdtags.t))210 kbdtags.wi = 0;211 if(kbdtags.wi == kbdtags.ri)212 sysfatal("too many queued keyboard reads");213 kbd.stall = 0;214 matchkbd();215 zunlock();216 break;218 case Tmoveto:219 setmouse(m->mouse.xy);220 replymsg(m);221 break;223 case Tcursor:224 if(m->arrowcursor)225 setcursor(nil);226 else227 setcursor(&m->cursor);228 replymsg(m);229 break;231 case Tbouncemouse:232 // _xbouncemouse(&m->mouse);233 replymsg(m);234 break;236 case Tlabel:237 kicklabel(m->label);238 replymsg(m);239 break;241 case Trdsnarf:242 m->snarf = getsnarf();243 replymsg(m);244 free(m->snarf);245 break;247 case Twrsnarf:248 putsnarf(m->snarf);249 replymsg(m);250 break;252 case Trddraw:253 n = m->count;254 if(n > sizeof buf)255 n = sizeof buf;256 n = _drawmsgread(buf, n);257 if(n < 0)258 replyerror(m);259 else{260 m->count = n;261 m->data = buf;262 replymsg(m);263 }264 break;266 case Twrdraw:267 if(_drawmsgwrite(m->data, m->count) < 0)268 replyerror(m);269 else270 replymsg(m);271 break;273 case Ttop:274 // _xtopwindow();275 replymsg(m);276 break;278 case Tresize:279 // _xresizewindow(m->rect);280 replymsg(m);281 break;282 }283 }285 /*286 * Reply to m.287 */288 QLock replylock;289 void290 replymsg(Wsysmsg *m)291 {292 int n;293 static uchar *mbuf;294 static int nmbuf;296 /* T -> R msg */297 if(m->type%2 == 0)298 m->type++;300 if(trace) fprint(2, "-> %W\n", m);301 /* copy to output buffer */302 n = sizeW2M(m);304 qlock(&replylock);305 if(n > nmbuf){306 free(mbuf);307 mbuf = malloc(n);308 if(mbuf == nil)309 sysfatal("out of memory");310 nmbuf = n;311 }312 convW2M(m, mbuf, n);313 if(write(4, mbuf, n) != n)314 sysfatal("write: %r");315 qunlock(&replylock);316 }318 /*319 * Match queued kbd reads with queued kbd characters.320 */321 void322 matchkbd(void)323 {324 Wsysmsg m;326 if(kbd.stall)327 return;328 while(kbd.ri != kbd.wi && kbdtags.ri != kbdtags.wi){329 m.type = Rrdkbd;330 m.tag = kbdtags.t[kbdtags.ri++];331 if(kbdtags.ri == nelem(kbdtags.t))332 kbdtags.ri = 0;333 m.rune = kbd.r[kbd.ri++];334 if(kbd.ri == nelem(kbd.r))335 kbd.ri = 0;336 replymsg(&m);337 }338 }340 /*341 * Match queued mouse reads with queued mouse events.342 */343 void344 matchmouse(void)345 {346 Wsysmsg m;348 while(mouse.ri != mouse.wi && mousetags.ri != mousetags.wi){349 m.type = Rrdmouse;350 m.tag = mousetags.t[mousetags.ri++];351 if(mousetags.ri == nelem(mousetags.t))352 mousetags.ri = 0;353 m.mouse = mouse.m[mouse.ri];354 m.resized = mouseresized;355 /*356 if(m.resized)357 fprint(2, "sending resize\n");358 */359 mouseresized = 0;360 mouse.ri++;361 if(mouse.ri == nelem(mouse.m))362 mouse.ri = 0;363 replymsg(&m);364 }365 }367 void368 mousetrack(int x, int y, int b, int ms)369 {370 Mouse *m;372 if(x < mouserect.min.x)373 x = mouserect.min.x;374 if(x > mouserect.max.x)375 x = mouserect.max.x;376 if(y < mouserect.min.y)377 y = mouserect.min.y;378 if(y > mouserect.max.y)379 y = mouserect.max.y;381 // zlock();382 // If reader has stopped reading, don't bother.383 // If reader is completely caught up, definitely queue.384 // Otherwise, queue only button change events.385 if(!mouse.stall)386 if(mouse.wi == mouse.ri || mouse.last.buttons != b){387 m = &mouse.last;388 m->xy.x = x;389 m->xy.y = y;390 m->buttons = b;391 m->msec = ms;393 mouse.m[mouse.wi] = *m;394 if(++mouse.wi == nelem(mouse.m))395 mouse.wi = 0;396 if(mouse.wi == mouse.ri){397 mouse.stall = 1;398 mouse.ri = 0;399 mouse.wi = 1;400 mouse.m[0] = *m;401 }402 matchmouse();403 }404 // zunlock();405 }407 void408 kputc(int c)409 {410 zlock();411 kbd.r[kbd.wi++] = c;412 if(kbd.wi == nelem(kbd.r))413 kbd.wi = 0;414 if(kbd.ri == kbd.wi)415 kbd.stall = 1;416 matchkbd();417 zunlock();418 }420 void421 keystroke(int c)422 {423 static Rune k[10];424 static int alting, nk;425 int i;427 if(c == Kalt){428 alting = !alting;429 return;430 }431 if(!alting){432 kputc(c);433 return;434 }435 if(nk >= nelem(k)) // should not happen436 nk = 0;437 k[nk++] = c;438 c = _latin1(k, nk);439 if(c > 0){440 alting = 0;441 kputc(c);442 nk = 0;443 return;444 }445 if(c == -1){446 alting = 0;447 for(i=0; i<nk; i++)448 kputc(k[i]);449 nk = 0;450 return;451 }452 // need more input453 return;454 }