Blob


1 #define Point OSXPoint
2 #define Rect OSXRect
3 #define Cursor OSXCursor
4 #import <AppKit/AppKit.h>
5 #undef Rect
6 #undef Point
7 #undef Cursor
9 /*
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 time
33 #define MouseMask (\
34 ButtonPressMask|\
35 ButtonReleaseMask|\
36 PointerMotionMask|\
37 Button1MotionMask|\
38 Button2MotionMask|\
39 Button3MotionMask)
41 #define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|EnterWindowMask|LeaveWindowMask
43 typedef struct Kbdbuf Kbdbuf;
44 typedef struct Mousebuf Mousebuf;
45 typedef struct Fdbuf Fdbuf;
46 typedef struct Tagbuf Tagbuf;
48 struct Kbdbuf
49 {
50 Rune r[32];
51 int ri;
52 int wi;
53 int stall;
54 };
56 struct Mousebuf
57 {
58 Mouse m[32];
59 Mouse last;
60 int ri;
61 int wi;
62 int stall;
63 };
65 struct Tagbuf
66 {
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 void
89 zlock(void)
90 {
91 qlock(&lk);
92 }
94 void
95 zunlock(void)
96 {
97 qunlock(&lk);
98 }
100 int chatty;
101 int drawsleep;
102 int trace;
104 void
105 usage(void)
107 fprint(2, "usage: devdraw (don't run directly)\n");
108 exits("usage");
111 void
112 bell(void *v, char *msg)
114 if(strcmp(msg, "alarm") == 0)
115 drawsleep = drawsleep ? 0 : 1000;
116 noted(NCONT);
119 int
120 main(int argc, char **argv)
122 NSAutoreleasePool *pool = nil;
123 NSApplication *application = nil;
124 DevdrawDelegate *app = nil;
125 /*
126 * Move the protocol off stdin/stdout so that
127 * 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 }ARGEND
147 /*
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;
164 void
165 replyerror(Wsysmsg *m)
167 char err[256];
169 rerrstr(err, sizeof err);
170 m->type = Rerror;
171 m->error = err;
172 replymsg(m);
175 /*
176 * Handle a single wsysmsg.
177 * Might queue for later (kbd, mouse read)
178 */
179 void
180 runmsg(Wsysmsg *m)
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 else
227 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);
264 break;
266 case Twrdraw:
267 if(_drawmsgwrite(m->data, m->count) < 0)
268 replyerror(m);
269 else
270 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;
285 /*
286 * Reply to m.
287 */
288 QLock replylock;
289 void
290 replymsg(Wsysmsg *m)
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;
312 convW2M(m, mbuf, n);
313 if(write(4, mbuf, n) != n)
314 sysfatal("write: %r");
315 qunlock(&replylock);
318 /*
319 * Match queued kbd reads with queued kbd characters.
320 */
321 void
322 matchkbd(void)
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);
340 /*
341 * Match queued mouse reads with queued mouse events.
342 */
343 void
344 matchmouse(void)
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);
367 void
368 mousetrack(int x, int y, int b, int ms)
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;
402 matchmouse();
404 // zunlock();
407 void
408 kputc(int c)
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();
420 void
421 keystroke(int c)
423 static Rune k[10];
424 static int alting, nk;
425 int i;
427 if(c == Kalt){
428 alting = !alting;
429 return;
431 if(!alting){
432 kputc(c);
433 return;
435 if(nk >= nelem(k)) // should not happen
436 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;
445 if(c == -1){
446 alting = 0;
447 for(i=0; i<nk; i++)
448 kputc(k[i]);
449 nk = 0;
450 return;
452 // need more input
453 return;