Blob
1 /*2 * Window system protocol server.3 * Use select and a single proc and single stack4 * to avoid aggravating the X11 library, which is5 * subtle and quick to anger.6 */8 #include <u.h>9 #include <sys/select.h>10 #include <errno.h>11 #include "x11-inc.h"12 #include <libc.h>13 #include <draw.h>14 #include <memdraw.h>15 #include <memlayer.h>16 #include <keyboard.h>17 #include <mouse.h>18 #include <cursor.h>19 #include <drawfcall.h>20 #include "x11-memdraw.h"21 #include "devdraw.h"23 #undef time25 #define MouseMask (\26 ButtonPressMask|\27 ButtonReleaseMask|\28 PointerMotionMask|\29 Button1MotionMask|\30 Button2MotionMask|\31 Button3MotionMask)33 #define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|EnterWindowMask|LeaveWindowMask35 typedef struct Kbdbuf Kbdbuf;36 typedef struct Mousebuf Mousebuf;37 typedef struct Fdbuf Fdbuf;38 typedef struct Tagbuf Tagbuf;40 struct Kbdbuf41 {42 Rune r[32];43 int ri;44 int wi;45 int stall;46 };48 struct Mousebuf49 {50 Mouse m[32];51 int resized[32];52 int ri;53 int wi;54 int stall;55 };57 struct Tagbuf58 {59 int t[32];60 int ri;61 int wi;62 };64 struct Fdbuf65 {66 uchar buf[2*MAXWMSG];67 uchar *rp;68 uchar *wp;69 uchar *ep;70 };72 Kbdbuf kbd;73 Mousebuf mouse;74 Fdbuf fdin;75 Fdbuf fdout;76 Tagbuf kbdtags;77 Tagbuf mousetags;78 Tagbuf resizetags;80 void fdslide(Fdbuf*);81 void runmsg(Wsysmsg*);82 void replymsg(Wsysmsg*);83 void runxevent(XEvent*);84 void matchkbd(void);85 void matchmouse(void);86 void matchresized(void);87 int fdnoblock(int);89 int chatty;91 void92 usage(void)93 {94 fprint(2, "usage: devdraw (don't run directly)\n");95 exits("usage");96 }98 void99 main(int argc, char **argv)100 {101 int n, top, firstx;102 fd_set rd, wr, xx;103 Wsysmsg m;104 XEvent event;106 ARGBEGIN{107 case 'D':108 chatty++;109 break;110 default:111 usage();112 }ARGEND114 if(argc != 0)115 usage();117 fdin.rp = fdin.wp = fdin.buf;118 fdin.ep = fdin.buf+sizeof fdin.buf;120 fdout.rp = fdout.wp = fdout.buf;121 fdout.ep = fdout.buf+sizeof fdout.buf;123 fdnoblock(0);124 fdnoblock(1);126 firstx = 1;127 _x.fd = -1;128 for(;;){129 /* set up file descriptors */130 FD_ZERO(&rd);131 FD_ZERO(&wr);132 FD_ZERO(&xx);133 /*134 * Don't read unless there's room *and* we haven't135 * already filled the output buffer too much.136 */137 if(fdout.wp < fdout.buf+MAXWMSG && fdin.wp < fdin.ep)138 FD_SET(0, &rd);139 if(fdout.wp > fdout.rp)140 FD_SET(1, &wr);141 FD_SET(0, &xx);142 FD_SET(1, &xx);143 top = 1;144 if(_x.fd >= 0){145 if(firstx){146 firstx = 0;147 XSelectInput(_x.display, _x.drawable, Mask);148 }149 FD_SET(_x.fd, &rd);150 FD_SET(_x.fd, &xx);151 XFlush(_x.display);152 top = _x.fd;153 }155 if(chatty)156 fprint(2, "select %d...\n", top+1);157 /* wait for something to happen */158 if(select(top+1, &rd, &wr, &xx, NULL) < 0){159 if(chatty)160 fprint(2, "select failure\n");161 exits(0);162 }163 if(chatty)164 fprint(2, "got select...\n");166 {167 /* read what we can */168 n = 1;169 while(fdin.wp < fdin.ep && (n = read(0, fdin.wp, fdin.ep-fdin.wp)) > 0)170 fdin.wp += n;171 if(n == 0){172 if(chatty)173 fprint(2, "eof\n");174 exits(0);175 }176 if(n < 0 && errno != EAGAIN)177 sysfatal("reading wsys msg: %r");179 /* pick off messages one by one */180 while((n = convM2W(fdin.rp, fdin.wp-fdin.rp, &m)) > 0){181 runmsg(&m);182 fdin.rp += n;183 }185 /* slide data to beginning of buf */186 fdslide(&fdin);187 }188 {189 /* write what we can */190 n = 1;191 while(fdout.rp < fdout.wp && (n = write(1, fdout.rp, fdout.wp-fdout.rp)) > 0)192 fdout.rp += n;193 if(n == 0)194 sysfatal("short write writing wsys");195 if(n < 0 && errno != EAGAIN)196 sysfatal("writing wsys msg: %r");198 /* slide data to beginning of buf */199 fdslide(&fdout);200 }201 {202 /*203 * Read an X message if we can.204 * (XPending actually calls select to make sure205 * the display's fd is readable and then reads206 * in any waiting data before declaring whether207 * there are events on the queue.)208 */209 while(XPending(_x.display)){210 XNextEvent(_x.display, &event);211 runxevent(&event);212 }213 }214 }215 }217 int218 fdnoblock(int fd)219 {220 return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)|O_NONBLOCK);221 }223 void224 fdslide(Fdbuf *fb)225 {226 int n;228 n = fb->wp - fb->rp;229 if(n > 0)230 memmove(fb->buf, fb->rp, n);231 fb->rp = fb->buf;232 fb->wp = fb->rp+n;233 }235 void236 replyerror(Wsysmsg *m)237 {238 char err[256];240 rerrstr(err, sizeof err);241 m->type = Rerror;242 m->error = err;243 replymsg(m);244 }246 /*247 * Handle a single wsysmsg.248 * Might queue for later (kbd, mouse read)249 */250 void251 runmsg(Wsysmsg *m)252 {253 uchar buf[65536];254 int n;255 Memimage *i;257 switch(m->type){258 case Tinit:259 memimageinit();260 i = _xattach(m->label, m->winsize);261 _initdisplaymemimage(i);262 replymsg(m);263 break;265 case Trdmouse:266 mousetags.t[mousetags.wi++] = m->tag;267 if(mousetags.wi == nelem(mousetags.t))268 mousetags.wi = 0;269 if(mousetags.wi == mousetags.ri)270 sysfatal("too many queued mouse reads");271 mouse.stall = 0;272 matchmouse();273 break;275 case Trdkbd:276 kbdtags.t[kbdtags.wi++] = m->tag;277 if(kbdtags.wi == nelem(kbdtags.t))278 kbdtags.wi = 0;279 if(kbdtags.wi == kbdtags.ri)280 sysfatal("too many queued keyboard reads");281 kbd.stall = 0;282 matchkbd();283 break;285 case Tmoveto:286 _xmoveto(m->mouse.xy);287 replymsg(m);288 break;290 case Tcursor:291 if(m->arrowcursor)292 _xsetcursor(nil);293 else294 _xsetcursor(&m->cursor);295 replymsg(m);296 break;298 case Tbouncemouse:299 _xbouncemouse(&m->mouse);300 replymsg(m);301 break;303 case Tlabel:304 _xsetlabel(m->label);305 replymsg(m);306 break;308 case Trdsnarf:309 m->snarf = _xgetsnarf();310 replymsg(m);311 free(m->snarf);312 break;314 case Twrsnarf:315 _xputsnarf(m->snarf);316 replymsg(m);317 break;319 case Trddraw:320 n = m->count;321 if(n > sizeof buf)322 n = sizeof buf;323 n = _drawmsgread(buf, n);324 if(n < 0)325 replyerror(m);326 else{327 m->count = n;328 m->data = buf;329 replymsg(m);330 }331 break;333 case Twrdraw:334 if(_drawmsgwrite(m->data, m->count) < 0)335 replyerror(m);336 else337 replymsg(m);338 break;340 case Ttop:341 _xtopwindow();342 replymsg(m);343 break;345 case Tresize:346 _xresizewindow(m->rect);347 replymsg(m);348 break;349 }350 }352 /*353 * Reply to m.354 */355 void356 replymsg(Wsysmsg *m)357 {358 int n;360 /* T -> R msg */361 if(m->type%2 == 0)362 m->type++;364 /* copy to output buffer */365 n = sizeW2M(m);366 if(fdout.wp+n > fdout.ep)367 sysfatal("out of space for reply message");368 convW2M(m, fdout.wp, n);369 fdout.wp += n;370 }372 /*373 * Match queued kbd reads with queued kbd characters.374 */375 void376 matchkbd(void)377 {378 Wsysmsg m;380 if(kbd.stall)381 return;382 while(kbd.ri != kbd.wi && kbdtags.ri != kbdtags.wi){383 m.type = Rrdkbd;384 m.tag = kbdtags.t[kbdtags.ri++];385 if(kbdtags.ri == nelem(kbdtags.t))386 kbdtags.ri = 0;387 m.rune = kbd.r[kbd.ri++];388 if(kbd.ri == nelem(kbd.r))389 kbd.ri = 0;390 replymsg(&m);391 }392 }394 /*395 * Match queued mouse reads with queued mouse events.396 */397 void398 matchmouse(void)399 {400 Wsysmsg m;402 if(mouse.stall)403 return;404 while(mouse.ri != mouse.wi && mousetags.ri != mousetags.wi){405 m.type = Rrdmouse;406 m.tag = mousetags.t[mousetags.ri++];407 if(mousetags.ri == nelem(mousetags.t))408 mousetags.ri = 0;409 m.mouse = mouse.m[mouse.ri];410 m.resized = mouse.resized[mouse.ri];411 mouse.ri++;412 if(mouse.ri == nelem(mouse.m))413 mouse.ri = 0;414 replymsg(&m);415 }416 }418 /*419 * Handle an incoming X event.420 */421 void422 runxevent(XEvent *xev)423 {424 int c;425 static Mouse m;427 switch(xev->type){428 case Expose:429 _xexpose(xev);430 break;432 case DestroyNotify:433 if(_xdestroy(xev))434 exits(0);435 break;437 case ConfigureNotify:438 if(_xconfigure(xev)){439 mouse.resized[mouse.wi] = 1;440 _xreplacescreenimage();441 goto addmouse;442 }443 break;445 case ButtonPress:446 case ButtonRelease:447 case MotionNotify:448 if(mouse.stall)449 return;450 if(_xtoplan9mouse(xev, &m) < 0)451 return;452 mouse.resized[mouse.wi] = 0;453 addmouse:454 mouse.m[mouse.wi] = m;455 mouse.wi++;456 if(mouse.wi == nelem(mouse.m))457 mouse.wi = 0;458 if(mouse.wi == mouse.ri)459 mouse.stall = 1;460 matchmouse();461 break;463 case KeyPress:464 if(kbd.stall)465 return;466 if((c = _xtoplan9kbd(xev)) < 0)467 return;468 kbd.r[kbd.wi++] = c;469 if(kbd.wi == nelem(kbd.r))470 kbd.wi = 0;471 if(kbd.ri == kbd.wi)472 kbd.stall = 1;473 matchkbd();474 break;476 case SelectionRequest:477 _xselect(xev);478 break;479 }480 }