blob: 6cbb523593df415f7fb6535a1ca39f0b17dcf1c3 [file] [log] [blame]
Russ Cox9142d362008-06-30 19:41:08 -04001/*
2 * Window system protocol server.
3 */
4
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"
19
20#undef time
21
22#define MouseMask (\
23 ButtonPressMask|\
24 ButtonReleaseMask|\
25 PointerMotionMask|\
26 Button1MotionMask|\
27 Button2MotionMask|\
28 Button3MotionMask)
29
30#define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|EnterWindowMask|LeaveWindowMask
31
32typedef struct Kbdbuf Kbdbuf;
33typedef struct Mousebuf Mousebuf;
34typedef struct Fdbuf Fdbuf;
35typedef struct Tagbuf Tagbuf;
36
37struct Kbdbuf
38{
39 Rune r[32];
40 int ri;
41 int wi;
42 int stall;
43};
44
45struct Mousebuf
46{
47 Mouse m[32];
Russ Cox1f74e1b2008-07-10 00:07:57 -040048 Mouse last;
Russ Cox9142d362008-06-30 19:41:08 -040049 int ri;
50 int wi;
51 int stall;
52};
53
54struct Tagbuf
55{
56 int t[32];
57 int ri;
58 int wi;
59};
60
61Kbdbuf kbd;
62Mousebuf mouse;
63Tagbuf kbdtags;
64Tagbuf mousetags;
65
66void fdslide(Fdbuf*);
67void runmsg(Wsysmsg*);
68void replymsg(Wsysmsg*);
69void matchkbd(void);
70void matchmouse(void);
71int fdnoblock(int);
72Rectangle mouserect;
73int mouseresized;
74
75
76QLock lk;
77void
78zlock(void)
79{
80 qlock(&lk);
81}
82
83void
84zunlock(void)
85{
86 qunlock(&lk);
87}
88
89int chatty;
90int drawsleep;
91int trace;
Russ Cox100ec442010-01-04 10:23:35 -080092int multitouch = 1;
Russ Cox9142d362008-06-30 19:41:08 -040093
94void
95usage(void)
96{
97 fprint(2, "usage: devdraw (don't run directly)\n");
98 threadexitsall("usage");
99}
100
101void
102bell(void *v, char *msg)
103{
104 if(strcmp(msg, "alarm") == 0)
105 drawsleep = drawsleep ? 0 : 1000;
106 noted(NCONT);
107}
108
109void
110threadmain(int argc, char **argv)
111{
112 uchar buf[4], *mbuf;
113 int nmbuf, n, nn;
114 Wsysmsg m;
115
116 /*
117 * Move the protocol off stdin/stdout so that
118 * 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);
126
127//trace = 1;
128 fmtinstall('W', drawfcallfmt);
129
130 ARGBEGIN{
131 case 'D':
132 chatty++;
133 break;
Russ Cox100ec442010-01-04 10:23:35 -0800134 case 'M':
135 multitouch = 0;
136 break;
Russ Cox9142d362008-06-30 19:41:08 -0400137 default:
138 usage();
139 }ARGEND
140
141 /*
142 * Ignore arguments. They're only for good ps -a listings.
143 */
144
145 notify(bell);
146
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");
162
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}
171
172void
173replyerror(Wsysmsg *m)
174{
175 char err[256];
176
177 rerrstr(err, sizeof err);
178 m->type = Rerror;
179 m->error = err;
180 replymsg(m);
181}
182
183/*
184 * Handle a single wsysmsg.
185 * Might queue for later (kbd, mouse read)
186 */
187void
188runmsg(Wsysmsg *m)
189{
190 static uchar buf[65536];
191 int n;
192 Memimage *i;
193
194 switch(m->type){
195 case Tinit:
196 memimageinit();
197 i = attachscreen(m->label, m->winsize);
198 _initdisplaymemimage(i);
199 replymsg(m);
200 break;
201
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");
Russ Cox9142d362008-06-30 19:41:08 -0400209 mouse.stall = 0;
210 matchmouse();
211 zunlock();
212 break;
213
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;
225
226 case Tmoveto:
227 setmouse(m->mouse.xy);
228 replymsg(m);
229 break;
230
231 case Tcursor:
232 if(m->arrowcursor)
233 setcursor(nil);
234 else
235 setcursor(&m->cursor);
236 replymsg(m);
237 break;
238
239 case Tbouncemouse:
240 // _xbouncemouse(&m->mouse);
241 replymsg(m);
242 break;
243
244 case Tlabel:
Russ Cox4a341062009-06-16 07:16:25 -0700245 kicklabel(m->label);
Russ Cox9142d362008-06-30 19:41:08 -0400246 replymsg(m);
247 break;
248
249 case Trdsnarf:
250 m->snarf = getsnarf();
251 replymsg(m);
252 free(m->snarf);
253 break;
254
255 case Twrsnarf:
256 putsnarf(m->snarf);
257 replymsg(m);
258 break;
259
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;
273
274 case Twrdraw:
275 if(_drawmsgwrite(m->data, m->count) < 0)
276 replyerror(m);
277 else
278 replymsg(m);
279 break;
280
281 case Ttop:
282 // _xtopwindow();
283 replymsg(m);
284 break;
285
286 case Tresize:
287 // _xresizewindow(m->rect);
288 replymsg(m);
289 break;
290 }
291}
292
293/*
294 * Reply to m.
295 */
Russ Cox607880c2008-10-08 14:59:32 -0700296QLock replylock;
Russ Cox9142d362008-06-30 19:41:08 -0400297void
298replymsg(Wsysmsg *m)
299{
300 int n;
301 static uchar *mbuf;
302 static int nmbuf;
303
304 /* T -> R msg */
305 if(m->type%2 == 0)
306 m->type++;
307
308 if(trace) fprint(2, "-> %W\n", m);
309 /* copy to output buffer */
310 n = sizeW2M(m);
Russ Cox607880c2008-10-08 14:59:32 -0700311
312 qlock(&replylock);
Russ Cox9142d362008-06-30 19:41:08 -0400313 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);
Russ Cox962d5a82008-07-04 12:39:01 -0400321 if(write(4, mbuf, n) != n)
322 sysfatal("write: %r");
Russ Cox607880c2008-10-08 14:59:32 -0700323 qunlock(&replylock);
Russ Cox9142d362008-06-30 19:41:08 -0400324}
325
326/*
327 * Match queued kbd reads with queued kbd characters.
328 */
329void
330matchkbd(void)
331{
332 Wsysmsg m;
333
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}
347
348/*
349 * Match queued mouse reads with queued mouse events.
350 */
351void
352matchmouse(void)
353{
354 Wsysmsg m;
355
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}
374
375void
376mousetrack(int x, int y, int b, int ms)
377{
378 Mouse *m;
379
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;
388
389 zlock();
Russ Cox1f74e1b2008-07-10 00:07:57 -0400390 // 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;
400
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();
Russ Cox9142d362008-06-30 19:41:08 -0400411 }
Russ Cox9142d362008-06-30 19:41:08 -0400412 zunlock();
413}
Russ Cox81a90f82008-07-01 20:45:49 -0400414
Russ Cox9142d362008-06-30 19:41:08 -0400415void
Russ Cox81a90f82008-07-01 20:45:49 -0400416kputc(int c)
Russ Cox9142d362008-06-30 19:41:08 -0400417{
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}
Russ Cox81a90f82008-07-01 20:45:49 -0400427
428void
429keystroke(int c)
430{
431 static Rune k[10];
432 static int alting, nk;
433 int i;
434
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 happen
444 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 input
461 return;
462}