aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/devdraw/cocoa-srv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/devdraw/cocoa-srv.c')
-rw-r--r--src/cmd/devdraw/cocoa-srv.c397
1 files changed, 397 insertions, 0 deletions
diff --git a/src/cmd/devdraw/cocoa-srv.c b/src/cmd/devdraw/cocoa-srv.c
new file mode 100644
index 00000000..507138f8
--- /dev/null
+++ b/src/cmd/devdraw/cocoa-srv.c
@@ -0,0 +1,397 @@
+/*
+ * Window system protocol server.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "cocoa-thread.h"
+#include <draw.h>
+#include <memdraw.h>
+#include <keyboard.h>
+#include <mouse.h>
+#include <cursor.h>
+#include <drawfcall.h>
+#include "cocoa-screen.h"
+#include "devdraw.h"
+
+typedef struct Kbdbuf Kbdbuf;
+typedef struct Mousebuf Mousebuf;
+typedef struct Fdbuf Fdbuf;
+typedef struct Tagbuf Tagbuf;
+
+struct Kbdbuf
+{
+ Rune r[32];
+ int ri;
+ int wi;
+ int stall;
+};
+
+struct Mousebuf
+{
+ Mouse m[32];
+ Mouse last;
+ int ri;
+ int wi;
+ int stall;
+};
+
+struct Tagbuf
+{
+ int t[32];
+ int ri;
+ int wi;
+};
+
+Kbdbuf kbd;
+Mousebuf mouse;
+Tagbuf kbdtags;
+Tagbuf mousetags;
+
+void runmsg(Wsysmsg*);
+void replymsg(Wsysmsg*);
+void matchkbd(void);
+void matchmouse(void);
+
+
+QLock lk;
+void
+zlock(void)
+{
+ qlock(&lk);
+}
+
+void
+zunlock(void)
+{
+ qunlock(&lk);
+}
+
+int trace = 0;
+
+void
+servep9p(void)
+{
+ uchar buf[4], *mbuf;
+ int nmbuf, n, nn;
+ Wsysmsg m;
+
+ fmtinstall('W', drawfcallfmt);
+
+// notify(bell);
+
+ mbuf = nil;
+ nmbuf = 0;
+ while((n = read(3, buf, 4)) == 4){
+ GET(buf, n);
+ if(n > nmbuf){
+ free(mbuf);
+ mbuf = malloc(4+n);
+ if(mbuf == nil)
+ sysfatal("malloc: %r");
+ nmbuf = n;
+ }
+ memmove(mbuf, buf, 4);
+ nn = readn(3, mbuf+4, n-4);
+ if(nn != n-4)
+ sysfatal("eof during message");
+
+ /* pick off messages one by one */
+ if(convM2W(mbuf, nn+4, &m) <= 0)
+ sysfatal("cannot convert message");
+ if(trace) fprint(2, "<- %W\n", &m);
+ runmsg(&m);
+ }
+}
+
+void
+replyerror(Wsysmsg *m)
+{
+ char err[256];
+
+ rerrstr(err, sizeof err);
+ m->type = Rerror;
+ m->error = err;
+ replymsg(m);
+}
+
+/*
+ * Handle a single wsysmsg.
+ * Might queue for later (kbd, mouse read)
+ */
+void
+runmsg(Wsysmsg *m)
+{
+ static uchar buf[65536];
+ int n;
+ Memimage *i;
+
+ switch(m->type){
+ case Tinit:
+ memimageinit();
+ i = attachscreen(m->label, m->winsize);
+ _initdisplaymemimage(i);
+ replymsg(m);
+ break;
+
+ case Trdmouse:
+ zlock();
+ mousetags.t[mousetags.wi++] = m->tag;
+ if(mousetags.wi == nelem(mousetags.t))
+ mousetags.wi = 0;
+ if(mousetags.wi == mousetags.ri)
+ sysfatal("too many queued mouse reads");
+ mouse.stall = 0;
+ matchmouse();
+ zunlock();
+ break;
+
+ case Trdkbd:
+ zlock();
+ kbdtags.t[kbdtags.wi++] = m->tag;
+ if(kbdtags.wi == nelem(kbdtags.t))
+ kbdtags.wi = 0;
+ if(kbdtags.wi == kbdtags.ri)
+ sysfatal("too many queued keyboard reads");
+ kbd.stall = 0;
+ matchkbd();
+ zunlock();
+ break;
+
+ case Tmoveto:
+ setmouse(m->mouse.xy);
+ replymsg(m);
+ break;
+
+ case Tcursor:
+ if(m->arrowcursor)
+ setcursor(nil);
+ else
+ setcursor(&m->cursor);
+ replymsg(m);
+ break;
+
+ case Tbouncemouse:
+ // _xbouncemouse(&m->mouse);
+ replymsg(m);
+ break;
+
+ case Tlabel:
+ kicklabel(m->label);
+ replymsg(m);
+ break;
+
+ case Trdsnarf:
+ m->snarf = getsnarf();
+ replymsg(m);
+ free(m->snarf);
+ break;
+
+ case Twrsnarf:
+ putsnarf(m->snarf);
+ replymsg(m);
+ break;
+
+ case Trddraw:
+ n = m->count;
+ if(n > sizeof buf)
+ n = sizeof buf;
+ n = _drawmsgread(buf, n);
+ if(n < 0)
+ replyerror(m);
+ else{
+ m->count = n;
+ m->data = buf;
+ replymsg(m);
+ }
+ break;
+
+ case Twrdraw:
+ if(_drawmsgwrite(m->data, m->count) < 0)
+ replyerror(m);
+ else
+ replymsg(m);
+ break;
+
+ case Ttop:
+ // _xtopwindow();
+ replymsg(m);
+ break;
+
+ case Tresize:
+ // _xresizewindow(m->rect);
+ replymsg(m);
+ break;
+ }
+}
+
+/*
+ * Reply to m.
+ */
+QLock replylock;
+void
+replymsg(Wsysmsg *m)
+{
+ int n;
+ static uchar *mbuf;
+ static int nmbuf;
+
+ /* T -> R msg */
+ if(m->type%2 == 0)
+ m->type++;
+
+ if(trace) fprint(2, "-> %W\n", m);
+ /* copy to output buffer */
+ n = sizeW2M(m);
+
+ qlock(&replylock);
+ if(n > nmbuf){
+ free(mbuf);
+ mbuf = malloc(n);
+ if(mbuf == nil)
+ sysfatal("out of memory");
+ nmbuf = n;
+ }
+ convW2M(m, mbuf, n);
+ if(write(4, mbuf, n) != n)
+ sysfatal("write: %r");
+ qunlock(&replylock);
+}
+
+/*
+ * Match queued kbd reads with queued kbd characters.
+ */
+void
+matchkbd(void)
+{
+ Wsysmsg m;
+
+ if(kbd.stall)
+ return;
+ while(kbd.ri != kbd.wi && kbdtags.ri != kbdtags.wi){
+ m.type = Rrdkbd;
+ m.tag = kbdtags.t[kbdtags.ri++];
+ if(kbdtags.ri == nelem(kbdtags.t))
+ kbdtags.ri = 0;
+ m.rune = kbd.r[kbd.ri++];
+ if(kbd.ri == nelem(kbd.r))
+ kbd.ri = 0;
+ replymsg(&m);
+ }
+}
+
+/*
+ * Match queued mouse reads with queued mouse events.
+ */
+void
+matchmouse(void)
+{
+ Wsysmsg m;
+
+ while(mouse.ri != mouse.wi && mousetags.ri != mousetags.wi){
+ m.type = Rrdmouse;
+ m.tag = mousetags.t[mousetags.ri++];
+ if(mousetags.ri == nelem(mousetags.t))
+ mousetags.ri = 0;
+ m.mouse = mouse.m[mouse.ri];
+ m.resized = mouseresized;
+ /*
+ if(m.resized)
+ fprint(2, "sending resize\n");
+ */
+ mouseresized = 0;
+ mouse.ri++;
+ if(mouse.ri == nelem(mouse.m))
+ mouse.ri = 0;
+ replymsg(&m);
+ }
+}
+
+void
+mousetrack(int x, int y, int b, int ms)
+{
+ Mouse *m;
+
+ if(x < mouserect.min.x)
+ x = mouserect.min.x;
+ if(x > mouserect.max.x)
+ x = mouserect.max.x;
+ if(y < mouserect.min.y)
+ y = mouserect.min.y;
+ if(y > mouserect.max.y)
+ y = mouserect.max.y;
+
+ zlock();
+ // If reader has stopped reading, don't bother.
+ // If reader is completely caught up, definitely queue.
+ // Otherwise, queue only button change events.
+ if(!mouse.stall)
+ if(mouse.wi == mouse.ri || mouse.last.buttons != b){
+ m = &mouse.last;
+ m->xy.x = x;
+ m->xy.y = y;
+ m->buttons = b;
+ m->msec = ms;
+
+ mouse.m[mouse.wi] = *m;
+ if(++mouse.wi == nelem(mouse.m))
+ mouse.wi = 0;
+ if(mouse.wi == mouse.ri){
+ mouse.stall = 1;
+ mouse.ri = 0;
+ mouse.wi = 1;
+ mouse.m[0] = *m;
+ }
+ matchmouse();
+ }
+ zunlock();
+}
+
+void
+kputc(int c)
+{
+ zlock();
+ kbd.r[kbd.wi++] = c;
+ if(kbd.wi == nelem(kbd.r))
+ kbd.wi = 0;
+ if(kbd.ri == kbd.wi)
+ kbd.stall = 1;
+ matchkbd();
+ zunlock();
+}
+
+void
+keystroke(int c)
+{
+ static Rune k[10];
+ static int alting, nk;
+ int i;
+
+ if(c == Kalt){
+ alting = !alting;
+ return;
+ }
+ if(!alting){
+ kputc(c);
+ return;
+ }
+ if(nk >= nelem(k)) // should not happen
+ nk = 0;
+ k[nk++] = c;
+ c = _latin1(k, nk);
+ if(c > 0){
+ alting = 0;
+ kputc(c);
+ nk = 0;
+ return;
+ }
+ if(c == -1){
+ alting = 0;
+ for(i=0; i<nk; i++)
+ kputc(k[i]);
+ nk = 0;
+ return;
+ }
+ // need more input
+ return;
+}