aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/devdraw/x11-srv.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2006-06-25 19:18:39 +0000
committerrsc <devnull@localhost>2006-06-25 19:18:39 +0000
commitc66b52501b630f6c0cdee1ed6cf81ad153e1183f (patch)
treeec935772fd77c3aa2337598c25a6c71ba84a9275 /src/cmd/devdraw/x11-srv.c
parentf97f53744067400bec4dbd7aae5eafde54e99b7f (diff)
downloadplan9port-c66b52501b630f6c0cdee1ed6cf81ad153e1183f.tar.gz
plan9port-c66b52501b630f6c0cdee1ed6cf81ad153e1183f.tar.bz2
plan9port-c66b52501b630f6c0cdee1ed6cf81ad153e1183f.zip
new draw server
Diffstat (limited to 'src/cmd/devdraw/x11-srv.c')
-rw-r--r--src/cmd/devdraw/x11-srv.c481
1 files changed, 481 insertions, 0 deletions
diff --git a/src/cmd/devdraw/x11-srv.c b/src/cmd/devdraw/x11-srv.c
new file mode 100644
index 00000000..a5c5bf11
--- /dev/null
+++ b/src/cmd/devdraw/x11-srv.c
@@ -0,0 +1,481 @@
+/*
+ * Window system protocol server.
+ * Use select and a single proc and single stack
+ * to avoid aggravating the X11 library, which is
+ * subtle and quick to anger.
+ */
+
+#include <u.h>
+#include <sys/select.h>
+#include <errno.h>
+#include "x11-inc.h"
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <memlayer.h>
+#include <keyboard.h>
+#include <mouse.h>
+#include <cursor.h>
+#include <drawfcall.h>
+#include "x11-memdraw.h"
+#include "devdraw.h"
+
+#undef time
+
+#define MouseMask (\
+ ButtonPressMask|\
+ ButtonReleaseMask|\
+ PointerMotionMask|\
+ Button1MotionMask|\
+ Button2MotionMask|\
+ Button3MotionMask)
+
+#define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|EnterWindowMask|LeaveWindowMask
+
+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];
+ int resized[32];
+ int ri;
+ int wi;
+ int stall;
+};
+
+struct Tagbuf
+{
+ int t[32];
+ int ri;
+ int wi;
+};
+
+struct Fdbuf
+{
+ uchar buf[2*MAXWMSG];
+ uchar *rp;
+ uchar *wp;
+ uchar *ep;
+};
+
+Kbdbuf kbd;
+Mousebuf mouse;
+Fdbuf fdin;
+Fdbuf fdout;
+Tagbuf kbdtags;
+Tagbuf mousetags;
+Tagbuf resizetags;
+
+void fdslide(Fdbuf*);
+void runmsg(Wsysmsg*);
+void replymsg(Wsysmsg*);
+void runxevent(XEvent*);
+void matchkbd(void);
+void matchmouse(void);
+void matchresized(void);
+int fdnoblock(int);
+
+int chatty;
+
+void
+usage(void)
+{
+ fprint(2, "usage: devdraw (don't run directly)\n");
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ int n, top, firstx;
+ fd_set rd, wr, xx;
+ Wsysmsg m;
+ XEvent event;
+
+ ARGBEGIN{
+ case 'D':
+ chatty++;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc != 0)
+ usage();
+
+ fdin.rp = fdin.wp = fdin.buf;
+ fdin.ep = fdin.buf+sizeof fdin.buf;
+
+ fdout.rp = fdout.wp = fdout.buf;
+ fdout.ep = fdout.buf+sizeof fdout.buf;
+
+ fdnoblock(0);
+ fdnoblock(1);
+
+ firstx = 1;
+ _x.fd = -1;
+ for(;;){
+ /* set up file descriptors */
+ FD_ZERO(&rd);
+ FD_ZERO(&wr);
+ FD_ZERO(&xx);
+ /*
+ * Don't read unless there's room *and* we haven't
+ * already filled the output buffer too much.
+ */
+ if(fdout.wp < fdout.buf+MAXWMSG && fdin.wp < fdin.ep)
+ FD_SET(0, &rd);
+ if(fdout.wp > fdout.rp)
+ FD_SET(1, &wr);
+ FD_SET(0, &xx);
+ FD_SET(1, &xx);
+ top = 1;
+ if(_x.fd >= 0){
+ if(firstx){
+ firstx = 0;
+ XSelectInput(_x.display, _x.drawable, Mask);
+ }
+ FD_SET(_x.fd, &rd);
+ FD_SET(_x.fd, &xx);
+ XFlush(_x.display);
+ top = _x.fd;
+ }
+
+ if(chatty)
+ fprint(2, "select %d...\n", top+1);
+ /* wait for something to happen */
+ if(select(top+1, &rd, &wr, &xx, NULL) < 0){
+ if(chatty)
+ fprint(2, "select failure\n");
+ exits(0);
+ }
+ if(chatty)
+ fprint(2, "got select...\n");
+
+ {
+ /* read what we can */
+ n = 1;
+ while(fdin.wp < fdin.ep && (n = read(0, fdin.wp, fdin.ep-fdin.wp)) > 0)
+ fdin.wp += n;
+ if(n == 0){
+ if(chatty)
+ fprint(2, "eof\n");
+ exits(0);
+ }
+ if(n < 0 && errno != EAGAIN)
+ sysfatal("reading wsys msg: %r");
+
+ /* pick off messages one by one */
+ while((n = convM2W(fdin.rp, fdin.wp-fdin.rp, &m)) > 0){
+ runmsg(&m);
+ fdin.rp += n;
+ }
+
+ /* slide data to beginning of buf */
+ fdslide(&fdin);
+ }
+ {
+ /* write what we can */
+ n = 1;
+ while(fdout.rp < fdout.wp && (n = write(1, fdout.rp, fdout.wp-fdout.rp)) > 0)
+ fdout.rp += n;
+ if(n == 0)
+ sysfatal("short write writing wsys");
+ if(n < 0 && errno != EAGAIN)
+ sysfatal("writing wsys msg: %r");
+
+ /* slide data to beginning of buf */
+ fdslide(&fdout);
+ }
+ {
+ /*
+ * Read an X message if we can.
+ * (XPending actually calls select to make sure
+ * the display's fd is readable and then reads
+ * in any waiting data before declaring whether
+ * there are events on the queue.)
+ */
+ while(XPending(_x.display)){
+ XNextEvent(_x.display, &event);
+ runxevent(&event);
+ }
+ }
+ }
+}
+
+int
+fdnoblock(int fd)
+{
+ return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)|O_NONBLOCK);
+}
+
+void
+fdslide(Fdbuf *fb)
+{
+ int n;
+
+ n = fb->wp - fb->rp;
+ if(n > 0)
+ memmove(fb->buf, fb->rp, n);
+ fb->rp = fb->buf;
+ fb->wp = fb->rp+n;
+}
+
+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)
+{
+ uchar buf[65536];
+ int n;
+ Memimage *i;
+
+ switch(m->type){
+ case Tinit:
+ memimageinit();
+ i = _xattach(m->label, m->winsize);
+ _initdisplaymemimage(i);
+ replymsg(m);
+ break;
+
+ case Trdmouse:
+ 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();
+ break;
+
+ case Trdkbd:
+ 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();
+ break;
+
+ case Tmoveto:
+ _xmoveto(m->mouse.xy);
+ replymsg(m);
+ break;
+
+ case Tcursor:
+ if(m->arrowcursor)
+ _xsetcursor(nil);
+ else
+ _xsetcursor(&m->cursor);
+ replymsg(m);
+ break;
+
+ case Tbouncemouse:
+ _xbouncemouse(&m->mouse);
+ replymsg(m);
+ break;
+
+ case Tlabel:
+ _xsetlabel(m->label);
+ replymsg(m);
+ break;
+
+ case Trdsnarf:
+ m->snarf = _xgetsnarf();
+ replymsg(m);
+ free(m->snarf);
+ break;
+
+ case Twrsnarf:
+ _xputsnarf(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.
+ */
+void
+replymsg(Wsysmsg *m)
+{
+ int n;
+
+ /* T -> R msg */
+ if(m->type%2 == 0)
+ m->type++;
+
+ /* copy to output buffer */
+ n = sizeW2M(m);
+ if(fdout.wp+n > fdout.ep)
+ sysfatal("out of space for reply message");
+ convW2M(m, fdout.wp, n);
+ fdout.wp += n;
+}
+
+/*
+ * 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;
+
+ if(mouse.stall)
+ return;
+ 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 = mouse.resized[mouse.ri];
+ mouse.ri++;
+ if(mouse.ri == nelem(mouse.m))
+ mouse.ri = 0;
+ replymsg(&m);
+ }
+}
+
+/*
+ * Handle an incoming X event.
+ */
+void
+runxevent(XEvent *xev)
+{
+ int c;
+ static Mouse m;
+
+ switch(xev->type){
+ case Expose:
+ _xexpose(xev);
+ break;
+
+ case DestroyNotify:
+ if(_xdestroy(xev))
+ exits(0);
+ break;
+
+ case ConfigureNotify:
+ if(_xconfigure(xev)){
+ mouse.resized[mouse.wi] = 1;
+ _xreplacescreenimage();
+ goto addmouse;
+ }
+ break;
+
+ case ButtonPress:
+ case ButtonRelease:
+ case MotionNotify:
+ if(mouse.stall)
+ return;
+ if(_xtoplan9mouse(xev, &m) < 0)
+ return;
+ mouse.resized[mouse.wi] = 0;
+ addmouse:
+ mouse.m[mouse.wi] = m;
+ mouse.wi++;
+ if(mouse.wi == nelem(mouse.m))
+ mouse.wi = 0;
+ if(mouse.wi == mouse.ri)
+ mouse.stall = 1;
+ matchmouse();
+ break;
+
+ case KeyPress:
+ if(kbd.stall)
+ return;
+ if((c = _xtoplan9kbd(xev)) < 0)
+ return;
+ kbd.r[kbd.wi++] = c;
+ if(kbd.wi == nelem(kbd.r))
+ kbd.wi = 0;
+ if(kbd.ri == kbd.wi)
+ kbd.stall = 1;
+ matchkbd();
+ break;
+
+ case SelectionRequest:
+ _xselect(xev);
+ break;
+ }
+}
+