14 #define MAXSNARF 100*1024
16 char Einuse[] = "file in use";
17 char Edeleted[] = "window deleted";
18 char Ebadreq[] = "bad graphics request";
19 char Etooshort[] = "buffer too small";
20 char Ebadtile[] = "unknown tile";
21 char Eshort[] = "short i/o request";
22 char Elong[] = "snarf buffer too long";
23 char Eunkid[] = "unknown id in attach";
24 char Ebadrect[] = "bad rectangle in attach";
25 char Ewindow[] = "cannot make window";
26 char Enowindow[] = "window has no image";
27 char Ebadmouse[] = "bad format on /dev/mouse";
28 char Ebadwrect[] = "rectangle outside screen";
29 char Ebadoffset[] = "window read not on scan line boundary";
32 static Xfid *xfidfree;
34 static Channel *cxfidalloc; /* chan(Xfid*) */
35 static Channel *cxfidfree; /* chan(Xfid*) */
41 xfidallocthread(void*)
44 enum { Alloc, Free, N };
47 alts[Alloc].c = cxfidalloc;
49 alts[Alloc].op = CHANRCV;
50 alts[Free].c = cxfidfree;
52 alts[Free].op = CHANRCV;
61 x = emalloc(sizeof(Xfid));
62 x->c = chancreate(sizeof(void(*)(Xfid*)), 0);
63 x->flushc = chancreate(sizeof(int), 0); /* notification only; no data */
67 threadcreate(xfidctl, x, 16384);
70 fprint(2, "%p incref %ld\n", x, x->ref);
74 error("flushtag in allocate");
80 fprint(2, "%p decref %ld\n", x, x->ref);
84 error("flushtag in free");
95 cxfidalloc = chancreate(sizeof(Xfid*), 0);
96 cxfidfree = chancreate(sizeof(Xfid*), 0);
97 threadcreate(xfidallocthread, nil, STACK);
109 snprint(buf, sizeof buf, "xfid.%p", x);
125 for(xf=xfid; xf; xf=xf->next)
126 if(xf->flushtag == x->oldtag){
129 incref(xf); /* to hold data structures up at tail of synchronization */
131 error("ref 1 in flush");
132 if(canqlock(&xf->active)){
133 qunlock(&xf->active);
134 sendul(xf->flushc, 0);
136 qlock(&xf->active); /* wait for him to finish */
137 qunlock(&xf->active);
139 xf->flushing = FALSE;
141 sendp(cxfidfree, xf);
144 filsysrespond(x->fs, x, &t, nil);
151 int id, hideit, scrollit;
153 char *err, *n, *dir, errbuf[ERRMAX];
165 if(x->aname[0] == 'N'){ /* N 100,100, 200, 200 - old syntax */
167 pid = strtoul(n, &n, 0);
170 r.min.x = strtoul(n, &n, 0);
173 r.min.y = strtoul(n, &n, 0);
176 r.max.x = strtoul(n, &n, 0);
179 r.max.y = strtoul(n, &n, 0);
185 i = allocimage(display, r, screen->chan, 0, DWhite);
187 i = allocwindow(wscreen, r, Refbackup, DWhite);
189 border(i, r, Selborder, display->black, ZP);
191 pid = -1; /* make sure we don't pop a shell! - UGH */
192 w = new(i, hideit, scrolling, pid, nil, nil, nil);
193 flushimage(display, 1);
198 }else if(strncmp(x->aname, "new", 3) == 0){ /* new -dx -dy - new syntax, as in wctl */
200 if(parsewctl(nil, ZR, &r, &pid, nil, &hideit, &scrollit, &dir, x->aname, errbuf) < 0)
212 filsysrespond(x->fs, x, &t, err);
215 if(!newlymade) /* counteract dec() in winshell() */
218 filsysrespond(x->fs, x, &t, nil);
229 filsysrespond(x->fs, x, &t, Edeleted);
232 switch(FILE(x->f->qid)){
235 filsysrespond(x->fs, x, &t, Einuse);
242 filsysrespond(x->fs, x, &t, Eperm);
248 filsysrespond(x->fs, x, &t, Einuse);
252 * Reshaped: there's a race if the appl. opens the
253 * window, is resized, and then opens the mouse,
254 * but that's rare. The alternative is to generate
255 * a resized event every time a new program starts
256 * up in a window that has been resized since the
257 * dawn of time. We choose the lesser evil.
263 if(x->mode==ORDWR || x->mode==OWRITE){
265 free(tsnarf); /* collision, but OK */
271 if(x->mode==OREAD || x->mode==ORDWR){
273 * It would be much nicer to implement fan-out for wctl reads,
274 * so multiple people can see the resizings, but rio just isn't
275 * structured for that. It's structured for /dev/cons, which gives
276 * alternate data to alternate readers. So to keep things sane for
277 * wctl, we compromise and give an error if two people try to
278 * open it. Apologies.
281 filsysrespond(x->fs, x, &t, Einuse);
286 wsendctlmesg(w, Wakeup, ZR, nil);
291 t.iounit = messagesize-IOHDRSZ;
293 x->f->mode = x->mode;
294 filsysrespond(x->fs, x, &t, nil);
305 switch(FILE(x->f->qid)){
309 wsendctlmesg(w, Rawoff, ZR, nil);
313 wsendctlmesg(w, Holdoff, ZR, nil);
319 wsetcursor(w, FALSE);
323 w->mouseopen = FALSE;
325 wsendctlmesg(w, Refresh, w->i->r, nil);
327 /* odd behavior but really ok: replace snarf buffer when /dev/snarf is closed */
329 if(x->f->mode==ORDWR || x->f->mode==OWRITE){
330 snarf = runerealloc(snarf, ntsnarf+1);
331 cvttorunes(tsnarf, ntsnarf, snarf, &nb, &nsnarf, &nulls);
338 if(x->f->mode==OREAD || x->f->mode==ORDWR)
343 filsysrespond(x->fs, x, &t, nil);
350 int c, cnt, qid, nb, off, nr;
357 enum { CWdata, CWflush, NCW };
362 filsysrespond(x->fs, x, &fc, Edeleted);
365 qid = FILE(x->f->qid);
373 memmove(x->data+nr, x->data, cnt); /* there's room: see malloc in filsysproc */
374 memmove(x->data, x->f->rpart, nr);
379 cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil);
380 /* approach end of buffer */
381 while(fullrune(x->data+nb, cnt-nb)){
383 nb += chartorune(&r[nr], x->data+c);
388 memmove(x->f->rpart, x->data+nb, cnt-nb);
389 x->f->nrpart = cnt-nb;
391 x->flushtag = x->tag;
393 alts[CWdata].c = w->conswrite;
394 alts[CWdata].v = &cwm;
395 alts[CWdata].op = CHANRCV;
396 alts[CWflush].c = x->flushc;
397 alts[CWflush].v = nil;
398 alts[CWflush].op = CHANRCV;
399 alts[NCW].op = CHANEND;
412 recv(x->flushc, nil); /* wake up flushing xfid */
413 pair.s = runemalloc(1);
415 send(cwm.cw, &pair); /* wake up window with empty data */
424 filsysrespond(x->fs, x, &fc, nil);
429 if(strncmp(x->data, "holdon", 6)==0){
430 if(w->holding++ == 0)
431 wsendctlmesg(w, Holdon, ZR, nil);
434 if(strncmp(x->data, "holdoff", 7)==0 && w->holding){
435 if(--w->holding == FALSE)
436 wsendctlmesg(w, Holdoff, ZR, nil);
439 if(strncmp(x->data, "rawon", 5)==0){
442 wsendctlmesg(w, Holdoff, ZR, nil);
445 wsendctlmesg(w, Rawon, ZR, nil);
448 if(strncmp(x->data, "rawoff", 6)==0 && w->rawing){
450 wsendctlmesg(w, Rawoff, ZR, nil);
453 filsysrespond(x->fs, x, &fc, "unknown control message");
460 w->cursor.offset.x = BGLONG(x->data+0*4);
461 w->cursor.offset.y = BGLONG(x->data+1*4);
462 memmove(w->cursor.clr, x->data+2*4, 2*2*16);
463 w->cursorp = &w->cursor;
465 wsetcursor(w, !sweeping);
470 filsysrespond(x->fs, x, &fc, "non-zero offset writing label");
474 w->label = emalloc(cnt+1);
475 memmove(w->label, x->data, cnt);
480 if(w!=input || Dx(w->screenr)<=0)
482 if(x->data[0] != 'm'){
483 filsysrespond(x->fs, x, &fc, Ebadmouse);
487 pt.x = strtoul(x->data+1, &p, 0);
489 filsysrespond(x->fs, x, &fc, Eshort);
492 pt.y = strtoul(p, nil, 0);
493 if(w==input && wpointto(mouse->xy)==w)
494 wsendctlmesg(w, Movemouse, Rpt(pt, pt), nil);
498 /* always append only */
499 if(ntsnarf > MAXSNARF){ /* avoid thrashing when people cut huge text */
500 filsysrespond(x->fs, x, &fc, Elong);
503 tsnarf = erealloc(tsnarf, ntsnarf+cnt+1); /* room for NUL */
504 memmove(tsnarf+ntsnarf, x->data, cnt);
512 if(x->data[cnt-1] == '\n'){
515 x->data[cnt-1] = '\0';
517 /* assume data comes in a single write */
519 * Problem: programs like dossrv, ftp produce illegal UTF;
520 * we must cope by converting it first.
522 snprint(buf, sizeof buf, "%.*s", cnt, x->data);
525 w->dir = estrdup(buf);
527 p = emalloc(strlen(w->dir) + 1 + strlen(buf) + 1);
528 sprint(p, "%s/%s", w->dir, buf);
530 w->dir = cleanname(p);
535 keyboardsend(x->data, cnt);
539 if(writewctl(x, buf) < 0){
540 filsysrespond(x->fs, x, &fc, buf);
543 flushimage(display, 1);
547 fprint(2, buf, "unknown qid %d in write\n", qid);
548 sprint(buf, "unknown qid in write");
549 filsysrespond(x->fs, x, &fc, buf);
553 filsysrespond(x->fs, x, &fc, nil);
557 readwindow(Image *i, char *t, Rectangle r, int offset, int n)
562 ww = bytesperline(r, screen->depth);
563 r.min.y += offset/ww;
564 if(r.min.y >= r.max.y)
569 if(r.max.y <= r.min.y)
571 return unloadimage(i, r, (uchar*)t, n);
586 Channel *c1, *c2; /* chan (tuple(char*, int)) */
591 enum { CRdata, CRflush, NCR };
592 enum { MRdata, MRflush, NMR };
593 enum { WCRdata, WCRflush, NWCR };
598 filsysrespond(x->fs, x, &fc, Edeleted);
601 qid = FILE(x->f->qid);
606 x->flushtag = x->tag;
608 alts[CRdata].c = w->consread;
609 alts[CRdata].v = &crm;
610 alts[CRdata].op = CHANRCV;
611 alts[CRflush].c = x->flushc;
612 alts[CRflush].v = nil;
613 alts[CRflush].op = CHANRCV;
614 alts[NMR].op = CHANEND;
628 t = malloc(cnt+UTFmax+1); /* room to unpack partial rune plus */
633 recv(x->flushc, nil); /* wake up flushing xfid */
634 recv(c2, nil); /* wake up window and toss data */
643 filsysrespond(x->fs, x, &fc, nil);
649 n = strlen(w->label);
654 fc.data = w->label+off;
656 filsysrespond(x->fs, x, &fc, nil);
660 x->flushtag = x->tag;
662 alts[MRdata].c = w->mouseread;
663 alts[MRdata].v = &mrm;
664 alts[MRdata].op = CHANRCV;
665 alts[MRflush].c = x->flushc;
666 alts[MRflush].v = nil;
667 alts[MRflush].op = CHANRCV;
668 alts[NMR].op = CHANEND;
681 recv(x->flushc, nil); /* wake up flushing xfid */
682 recv(mrm.cm, nil); /* wake up window and toss data */
691 n = sprint(buf, "%c%11d %11d %11d %11ld ", c, ms.xy.x, ms.xy.y, ms.buttons, ms.msec);
694 fc.count = min(n, cnt);
695 filsysrespond(x->fs, x, &fc, nil);
700 filsysrespond(x->fs, x, &fc, "cursor read not implemented");
703 /* The algorithm for snarf and text is expensive but easy and rarely used */
707 t = runetobyte(snarf, nsnarf, &n);
715 t = wcontents(w, &n);
727 filsysrespond(x->fs, x, &fc, nil);
737 n = sprint(buf, "%11d ", w->id);
745 filsysrespond(x->fs, x, &fc, "window has no name");
748 t = estrdup(w->name);
753 if(i == nil || Dx(w->screenr)<=0){
754 filsysrespond(x->fs, x, &fc, Enowindow);
763 filsysrespond(x->fs, x, &fc, "no top-level screen");
771 n = sprint(buf, "%11s %11d %11d %11d %11d ",
772 chantostr(cbuf, screen->chan),
773 i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y);
779 n = readwindow(i, t, r, off, cnt); /* careful; fc.count is unsigned */
782 errstr(buf, sizeof buf);
783 filsysrespond(x->fs, x, &fc, buf);
786 filsysrespond(x->fs, x, &fc, nil);
791 case Qwctl: /* read returns rectangle, hangs if not resized */
793 filsysrespond(x->fs, x, &fc, Etooshort);
796 x->flushtag = x->tag;
798 alts[WCRdata].c = w->wctlread;
799 alts[WCRdata].v = &cwrm;
800 alts[WCRdata].op = CHANRCV;
801 alts[WCRflush].c = x->flushc;
802 alts[WCRflush].v = nil;
803 alts[WCRflush].op = CHANRCV;
804 alts[NMR].op = CHANEND;
818 t = malloc(cnt+1); /* be sure to have room for NUL */
823 recv(x->flushc, nil); /* wake up flushing xfid */
824 recv(c2, nil); /* wake up window and toss data */
835 filsysrespond(x->fs, x, &fc, nil);
841 fprint(2, "unknown qid %d in read\n", qid);
842 sprint(buf, "unknown qid in read");
843 filsysrespond(x->fs, x, &fc, buf);