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];
164 scrollit = scrolling;
166 if(x->aname[0] == 'N'){ /* N 100,100, 200, 200 - old syntax */
168 pid = strtoul(n, &n, 0);
171 r.min.x = strtoul(n, &n, 0);
174 r.min.y = strtoul(n, &n, 0);
177 r.max.x = strtoul(n, &n, 0);
180 r.max.y = strtoul(n, &n, 0);
186 i = allocimage(display, r, screen->chan, 0, DWhite);
188 i = allocwindow(wscreen, r, Refbackup, DWhite);
190 border(i, r, Selborder, display->black, ZP);
192 pid = -1; /* make sure we don't pop a shell! - UGH */
193 w = new(i, hideit, scrollit, pid, nil, nil, nil);
194 flushimage(display, 1);
199 }else if(strncmp(x->aname, "new", 3) == 0){ /* new -dx -dy - new syntax, as in wctl */
201 if(parsewctl(nil, ZR, &r, &pid, nil, &hideit, &scrollit, &dir, x->aname, errbuf) < 0)
213 filsysrespond(x->fs, x, &t, err);
216 if(!newlymade) /* counteract dec() in winshell() */
219 filsysrespond(x->fs, x, &t, nil);
230 filsysrespond(x->fs, x, &t, Edeleted);
233 switch(FILE(x->f->qid)){
236 filsysrespond(x->fs, x, &t, Einuse);
243 filsysrespond(x->fs, x, &t, Eperm);
249 filsysrespond(x->fs, x, &t, Einuse);
256 filsysrespond(x->fs, x, &t, Einuse);
260 * Reshaped: there's a race if the appl. opens the
261 * window, is resized, and then opens the mouse,
262 * but that's rare. The alternative is to generate
263 * a resized event every time a new program starts
264 * up in a window that has been resized since the
265 * dawn of time. We choose the lesser evil.
271 if(x->mode==ORDWR || x->mode==OWRITE){
273 free(tsnarf); /* collision, but OK */
279 if(x->mode==OREAD || x->mode==ORDWR){
281 * It would be much nicer to implement fan-out for wctl reads,
282 * so multiple people can see the resizings, but rio just isn't
283 * structured for that. It's structured for /dev/cons, which gives
284 * alternate data to alternate readers. So to keep things sane for
285 * wctl, we compromise and give an error if two people try to
286 * open it. Apologies.
289 filsysrespond(x->fs, x, &t, Einuse);
294 wsendctlmesg(w, Wakeup, ZR, nil);
299 t.iounit = messagesize-IOHDRSZ;
301 x->f->mode = x->mode;
302 filsysrespond(x->fs, x, &t, nil);
313 switch(FILE(x->f->qid)){
317 wsendctlmesg(w, Rawoff, ZR, nil);
321 wsendctlmesg(w, Holdoff, ZR, nil);
327 wsetcursor(w, FALSE);
334 w->mouseopen = FALSE;
336 wsendctlmesg(w, Refresh, w->i->r, nil);
338 /* odd behavior but really ok: replace snarf buffer when /dev/snarf is closed */
340 if(x->f->mode==ORDWR || x->f->mode==OWRITE){
341 snarf = runerealloc(snarf, ntsnarf+1);
342 cvttorunes(tsnarf, ntsnarf, snarf, &nb, &nsnarf, &nulls);
349 if(x->f->mode==OREAD || x->f->mode==ORDWR)
354 filsysrespond(x->fs, x, &t, nil);
361 int c, cnt, qid, nb, off, nr;
368 enum { CWdata, CWflush, NCW };
373 filsysrespond(x->fs, x, &fc, Edeleted);
376 qid = FILE(x->f->qid);
384 memmove(x->data+nr, x->data, cnt); /* there's room: see malloc in filsysproc */
385 memmove(x->data, x->f->rpart, nr);
390 cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil);
391 /* approach end of buffer */
392 while(fullrune(x->data+nb, cnt-nb)){
394 nb += chartorune(&r[nr], x->data+c);
399 memmove(x->f->rpart, x->data+nb, cnt-nb);
400 x->f->nrpart = cnt-nb;
402 x->flushtag = x->tag;
404 alts[CWdata].c = w->conswrite;
405 alts[CWdata].v = &cwm;
406 alts[CWdata].op = CHANRCV;
407 alts[CWflush].c = x->flushc;
408 alts[CWflush].v = nil;
409 alts[CWflush].op = CHANRCV;
410 alts[NCW].op = CHANEND;
423 recv(x->flushc, nil); /* wake up flushing xfid */
424 pair.s = runemalloc(1);
426 send(cwm.cw, &pair); /* wake up window with empty data */
435 filsysrespond(x->fs, x, &fc, nil);
440 if(strncmp(x->data, "holdon", 6)==0){
441 if(w->holding++ == 0)
442 wsendctlmesg(w, Holdon, ZR, nil);
445 if(strncmp(x->data, "holdoff", 7)==0 && w->holding){
446 if(--w->holding == FALSE)
447 wsendctlmesg(w, Holdoff, ZR, nil);
450 if(strncmp(x->data, "rawon", 5)==0){
453 wsendctlmesg(w, Holdoff, ZR, nil);
456 wsendctlmesg(w, Rawon, ZR, nil);
459 if(strncmp(x->data, "rawoff", 6)==0 && w->rawing){
461 wsendctlmesg(w, Rawoff, ZR, nil);
464 filsysrespond(x->fs, x, &fc, "unknown control message");
471 w->cursor.offset.x = BGLONG(x->data+0*4);
472 w->cursor.offset.y = BGLONG(x->data+1*4);
473 memmove(w->cursor.clr, x->data+2*4, 2*2*16);
474 w->cursorp = &w->cursor;
476 wsetcursor(w, !sweeping);
481 filsysrespond(x->fs, x, &fc, "non-zero offset writing label");
485 w->label = emalloc(cnt+1);
486 memmove(w->label, x->data, cnt);
491 if(w!=input || Dx(w->screenr)<=0)
493 if(x->data[0] != 'm'){
494 filsysrespond(x->fs, x, &fc, Ebadmouse);
498 pt.x = strtoul(x->data+1, &p, 0);
500 filsysrespond(x->fs, x, &fc, Eshort);
503 pt.y = strtoul(p, nil, 0);
504 if(w==input && wpointto(mouse->xy)==w)
505 wsendctlmesg(w, Movemouse, Rpt(pt, pt), nil);
509 /* always append only */
510 if(ntsnarf > MAXSNARF){ /* avoid thrashing when people cut huge text */
511 filsysrespond(x->fs, x, &fc, Elong);
514 tsnarf = erealloc(tsnarf, ntsnarf+cnt+1); /* room for NUL */
515 memmove(tsnarf+ntsnarf, x->data, cnt);
523 if(x->data[cnt-1] == '\n'){
526 x->data[cnt-1] = '\0';
528 /* assume data comes in a single write */
530 * Problem: programs like dossrv, ftp produce illegal UTF;
531 * we must cope by converting it first.
533 snprint(buf, sizeof buf, "%.*s", cnt, x->data);
536 w->dir = estrdup(buf);
538 p = emalloc(strlen(w->dir) + 1 + strlen(buf) + 1);
539 sprint(p, "%s/%s", w->dir, buf);
541 w->dir = cleanname(p);
546 keyboardsend(x->data, cnt);
550 if(writewctl(x, buf) < 0){
551 filsysrespond(x->fs, x, &fc, buf);
554 flushimage(display, 1);
558 fprint(2, buf, "unknown qid %d in write\n", qid);
559 sprint(buf, "unknown qid in write");
560 filsysrespond(x->fs, x, &fc, buf);
564 filsysrespond(x->fs, x, &fc, nil);
568 readwindow(Image *i, char *t, Rectangle r, int offset, int n)
573 ww = bytesperline(r, i->depth);
574 r.min.y += offset/ww;
575 if(r.min.y >= r.max.y)
577 y = r.min.y + (n + ww-1)/ww;
582 if(oo == 0 && n >= m)
583 return unloadimage(i, r, (uchar*)t, n);
584 if((tt = malloc(m)) == nil)
586 m = unloadimage(i, r, tt, m) - oo;
589 memmove(t, tt + oo, m);
607 Channel *c1, *c2; /* chan (tuple(char*, int)) */
613 enum { CRdata, CRflush, NCR };
614 enum { MRdata, MRflush, NMR };
615 enum { WCRdata, WCRflush, NWCR };
620 filsysrespond(x->fs, x, &fc, Edeleted);
623 qid = FILE(x->f->qid);
628 x->flushtag = x->tag;
630 alts[CRdata].c = w->consread;
631 alts[CRdata].v = &crm;
632 alts[CRdata].op = CHANRCV;
633 alts[CRflush].c = x->flushc;
634 alts[CRflush].v = nil;
635 alts[CRflush].op = CHANRCV;
636 alts[NMR].op = CHANEND;
650 t = malloc(cnt+UTFmax+1); /* room to unpack partial rune plus */
655 recv(x->flushc, nil); /* wake up flushing xfid */
656 recv(c2, nil); /* wake up window and toss data */
665 filsysrespond(x->fs, x, &fc, nil);
671 n = strlen(w->label);
676 fc.data = w->label+off;
678 filsysrespond(x->fs, x, &fc, nil);
682 x->flushtag = x->tag;
684 alts[MRdata].c = w->mouseread;
685 alts[MRdata].v = &mrm;
686 alts[MRdata].op = CHANRCV;
687 alts[MRflush].c = x->flushc;
688 alts[MRflush].v = nil;
689 alts[MRflush].op = CHANRCV;
690 alts[NMR].op = CHANEND;
703 recv(x->flushc, nil); /* wake up flushing xfid */
704 recv(mrm.cm, nil); /* wake up window and toss data */
713 n = sprint(buf, "%c%11d %11d %11d %11ld ", c, ms.xy.x, ms.xy.y, ms.buttons, ms.msec);
716 fc.count = min(n, cnt);
717 filsysrespond(x->fs, x, &fc, nil);
722 x->flushtag = x->tag;
724 alts[MRdata].c = w->kbdread;
725 alts[MRdata].v = &krm;
726 alts[MRdata].op = CHANRCV;
727 alts[MRflush].c = x->flushc;
728 alts[MRflush].v = nil;
729 alts[MRflush].op = CHANRCV;
730 alts[NMR].op = CHANEND;
744 free(t); /* wake up window and toss data */
745 recv(x->flushc, nil); /* wake up flushing xfid */
751 fc.count = strlen(t)+1;
752 filsysrespond(x->fs, x, &fc, nil);
758 filsysrespond(x->fs, x, &fc, "cursor read not implemented");
761 /* The algorithm for snarf and text is expensive but easy and rarely used */
765 t = runetobyte(snarf, nsnarf, &n);
773 t = wcontents(w, &n);
785 filsysrespond(x->fs, x, &fc, nil);
795 n = sprint(buf, "%11d ", w->id);
803 filsysrespond(x->fs, x, &fc, "window has no name");
806 t = estrdup(w->name);
812 if(i == nil || Dx(r)<=0){
813 filsysrespond(x->fs, x, &fc, Enowindow);
824 n = sprint(buf, "%11s %11d %11d %11d %11d ",
825 chantostr(cbuf, i->chan),
826 r.min.x, r.min.y, r.max.x, r.max.y);
833 n = readwindow(i, t, r, off, cnt); /* careful; fc.count is unsigned */
836 errstr(buf, sizeof buf);
837 filsysrespond(x->fs, x, &fc, buf);
840 filsysrespond(x->fs, x, &fc, nil);
845 case Qwctl: /* read returns rectangle, hangs if not resized */
847 filsysrespond(x->fs, x, &fc, Etooshort);
850 x->flushtag = x->tag;
852 alts[WCRdata].c = w->wctlread;
853 alts[WCRdata].v = &cwrm;
854 alts[WCRdata].op = CHANRCV;
855 alts[WCRflush].c = x->flushc;
856 alts[WCRflush].v = nil;
857 alts[WCRflush].op = CHANRCV;
858 alts[NMR].op = CHANEND;
872 t = malloc(cnt+1); /* be sure to have room for NUL */
877 recv(x->flushc, nil); /* wake up flushing xfid */
878 recv(c2, nil); /* wake up window and toss data */
889 filsysrespond(x->fs, x, &fc, nil);
895 fprint(2, "unknown qid %d in read\n", qid);
896 sprint(buf, "unknown qid in read");
897 filsysrespond(x->fs, x, &fc, buf);