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);
114 x->flushtag = x->tag;
128 for(xf=xfid; xf; xf=xf->next)
129 if(xf->flushtag == x->oldtag){
130 incref(xf); /* to hold data structures up at tail of synchronization */
132 error("ref 1 in flush");
137 /* take over flushtag so follow up flushes wait for us */
138 x->flushtag = x->oldtag;
141 * wakeup filsysflush() in the filsysproc so the next
144 sendul(x->fs->csyncflush, 0);
147 enum { Done, Flush, End };
155 alts[Done].c = xf->c;
157 alts[Done].op = CHANSND;
158 alts[Flush].c = xf->flushc;
160 alts[Flush].op = CHANSND;
161 alts[End].op = CHANEND;
163 while(alt(alts) != Done)
166 if(nbrecv(x->flushc, nil)){
170 filsysrespond(x->fs, x, &t, nil);
177 int id, hideit, scrollit;
179 char *err, *n, *dir, errbuf[ERRMAX];
190 scrollit = scrolling;
192 if(x->aname[0] == 'N'){ /* N 100,100, 200, 200 - old syntax */
194 pid = strtoul(n, &n, 0);
197 r.min.x = strtoul(n, &n, 0);
200 r.min.y = strtoul(n, &n, 0);
203 r.max.x = strtoul(n, &n, 0);
206 r.max.y = strtoul(n, &n, 0);
212 i = allocimage(display, r, screen->chan, 0, DNofill);
214 i = allocwindow(wscreen, r, Refbackup, DNofill);
217 pid = -1; /* make sure we don't pop a shell! - UGH */
218 w = new(i, hideit, scrollit, pid, nil, nil, nil);
223 }else if(strncmp(x->aname, "new", 3) == 0){ /* new -dx -dy - new syntax, as in wctl */
225 if(parsewctl(nil, ZR, &r, &pid, nil, &hideit, &scrollit, &dir, x->aname, errbuf) < 0)
237 filsysrespond(x->fs, x, &t, err);
240 if(!newlymade) /* counteract dec() in winshell() */
243 filsysrespond(x->fs, x, &t, nil);
254 filsysrespond(x->fs, x, &t, Edeleted);
257 switch(FILE(x->f->qid)){
260 filsysrespond(x->fs, x, &t, Einuse);
267 filsysrespond(x->fs, x, &t, Eperm);
273 filsysrespond(x->fs, x, &t, Einuse);
280 filsysrespond(x->fs, x, &t, Einuse);
284 * Reshaped: there's a race if the appl. opens the
285 * window, is resized, and then opens the mouse,
286 * but that's rare. The alternative is to generate
287 * a resized event every time a new program starts
288 * up in a window that has been resized since the
289 * dawn of time. We choose the lesser evil.
295 if(x->mode==ORDWR || x->mode==OWRITE){
297 free(tsnarf); /* collision, but OK */
303 if(x->mode==OREAD || x->mode==ORDWR){
305 * It would be much nicer to implement fan-out for wctl reads,
306 * so multiple people can see the resizings, but rio just isn't
307 * structured for that. It's structured for /dev/cons, which gives
308 * alternate data to alternate readers. So to keep things sane for
309 * wctl, we compromise and give an error if two people try to
310 * open it. Apologies.
313 filsysrespond(x->fs, x, &t, Einuse);
318 wsendctlmesg(w, Wakeup, ZR, nil);
323 t.iounit = messagesize-IOHDRSZ;
325 x->f->mode = x->mode;
326 filsysrespond(x->fs, x, &t, nil);
337 switch(FILE(x->f->qid)){
341 wsendctlmesg(w, Rawoff, ZR, nil);
345 wsendctlmesg(w, Holdoff, ZR, nil);
351 wsetcursor(w, FALSE);
358 w->mouseopen = FALSE;
360 wsendctlmesg(w, Refresh, w->i->r, nil);
362 /* odd behavior but really ok: replace snarf buffer when /dev/snarf is closed */
364 if(x->f->mode==ORDWR || x->f->mode==OWRITE){
365 snarf = runerealloc(snarf, ntsnarf+1);
366 cvttorunes(tsnarf, ntsnarf, snarf, &nb, &nsnarf, &nulls);
373 if(x->f->mode==OREAD || x->f->mode==ORDWR)
378 filsysrespond(x->fs, x, &t, nil);
385 int c, cnt, qid, nb, off, nr;
392 enum { CWdata, CWgone, CWflush, NCW };
397 filsysrespond(x->fs, x, &fc, Edeleted);
400 qid = FILE(x->f->qid);
408 memmove(x->data+nr, x->data, cnt); /* there's room: see malloc in filsysproc */
409 memmove(x->data, x->f->rpart, nr);
414 cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil);
415 /* approach end of buffer */
416 while(fullrune(x->data+nb, cnt-nb)){
418 nb += chartorune(&r[nr], x->data+c);
423 memmove(x->f->rpart, x->data+nb, cnt-nb);
424 x->f->nrpart = cnt-nb;
427 alts[CWdata].c = w->conswrite;
428 alts[CWdata].v = &cwm;
429 alts[CWdata].op = CHANRCV;
430 alts[CWgone].c = w->gone;
431 alts[CWgone].v = nil;
432 alts[CWgone].op = CHANRCV;
433 alts[CWflush].c = x->flushc;
434 alts[CWflush].v = nil;
435 alts[CWflush].op = CHANRCV;
436 alts[NCW].op = CHANEND;
442 filsysrespond(x->fs, x, &fc, Edeleted);
456 filsysrespond(x->fs, x, &fc, nil);
460 if(strncmp(x->data, "holdon", 6)==0){
461 if(w->holding++ == 0)
462 wsendctlmesg(w, Holdon, ZR, nil);
465 if(strncmp(x->data, "holdoff", 7)==0 && w->holding){
466 if(--w->holding == 0)
467 wsendctlmesg(w, Holdoff, ZR, nil);
470 if(strncmp(x->data, "rawon", 5)==0){
473 wsendctlmesg(w, Holdoff, ZR, nil);
476 wsendctlmesg(w, Rawon, ZR, nil);
479 if(strncmp(x->data, "rawoff", 6)==0 && w->rawing){
481 wsendctlmesg(w, Rawoff, ZR, nil);
484 filsysrespond(x->fs, x, &fc, "unknown control message");
491 w->cursor.offset.x = BGLONG(x->data+0*4);
492 w->cursor.offset.y = BGLONG(x->data+1*4);
493 memmove(w->cursor.clr, x->data+2*4, 2*2*16);
494 w->cursorp = &w->cursor;
496 wsetcursor(w, !sweeping);
501 filsysrespond(x->fs, x, &fc, "non-zero offset writing label");
505 w->label = emalloc(cnt+1);
506 memmove(w->label, x->data, cnt);
511 if(w!=input || Dx(w->screenr)<=0)
513 if(x->data[0] != 'm'){
514 filsysrespond(x->fs, x, &fc, Ebadmouse);
518 pt.x = strtoul(x->data+1, &p, 0);
520 filsysrespond(x->fs, x, &fc, Eshort);
523 pt.y = strtoul(p, nil, 0);
524 if(w==input && wpointto(mouse->xy)==w)
525 wsendctlmesg(w, Movemouse, Rpt(pt, pt), nil);
529 /* always append only */
530 if(ntsnarf > MAXSNARF){ /* avoid thrashing when people cut huge text */
531 filsysrespond(x->fs, x, &fc, Elong);
534 tsnarf = erealloc(tsnarf, ntsnarf+cnt+1); /* room for NUL */
535 memmove(tsnarf+ntsnarf, x->data, cnt);
543 if(x->data[cnt-1] == '\n'){
546 x->data[cnt-1] = '\0';
548 /* assume data comes in a single write */
550 * Problem: programs like dossrv, ftp produce illegal UTF;
551 * we must cope by converting it first.
553 snprint(buf, sizeof buf, "%.*s", cnt, x->data);
556 w->dir = estrdup(buf);
558 p = emalloc(strlen(w->dir) + 1 + strlen(buf) + 1);
559 sprint(p, "%s/%s", w->dir, buf);
561 w->dir = cleanname(p);
566 keyboardsend(x->data, cnt);
570 if(writewctl(x, buf) < 0){
571 filsysrespond(x->fs, x, &fc, buf);
577 fprint(2, "unknown qid %d in write\n", qid);
578 snprint(buf, sizeof(buf), "unknown qid in write");
579 filsysrespond(x->fs, x, &fc, buf);
583 filsysrespond(x->fs, x, &fc, nil);
587 readwindow(Image *i, char *t, Rectangle r, int offset, int n)
592 ww = bytesperline(r, i->depth);
593 r.min.y += offset/ww;
594 if(r.min.y >= r.max.y)
596 y = r.min.y + (n + ww-1)/ww;
601 if(oo == 0 && n >= m)
602 return unloadimage(i, r, (uchar*)t, n);
603 if((tt = malloc(m)) == nil)
605 m = unloadimage(i, r, tt, m) - oo;
608 memmove(t, tt + oo, m);
626 Channel *c1, *c2; /* chan (tuple(char*, int)) */
632 enum { CRdata, CRgone, CRflush, NCR };
633 enum { MRdata, MRgone, MRflush, NMR };
634 enum { WCRdata, WCRgone, WCRflush, NWCR };
639 filsysrespond(x->fs, x, &fc, Edeleted);
642 qid = FILE(x->f->qid);
647 alts[CRdata].c = w->consread;
648 alts[CRdata].v = &crm;
649 alts[CRdata].op = CHANRCV;
650 alts[CRgone].c = w->gone;
651 alts[CRgone].v = nil;
652 alts[CRgone].op = CHANRCV;
653 alts[CRflush].c = x->flushc;
654 alts[CRflush].v = nil;
655 alts[CRflush].op = CHANRCV;
656 alts[NMR].op = CHANEND;
662 filsysrespond(x->fs, x, &fc, Edeleted);
672 t = malloc(cnt+UTFmax+1); /* room to unpack partial rune plus */
679 filsysrespond(x->fs, x, &fc, nil);
684 n = strlen(w->label);
689 fc.data = w->label+off;
691 filsysrespond(x->fs, x, &fc, nil);
695 alts[MRdata].c = w->mouseread;
696 alts[MRdata].v = &mrm;
697 alts[MRdata].op = CHANRCV;
698 alts[MRgone].c = w->gone;
699 alts[MRgone].v = nil;
700 alts[MRgone].op = CHANRCV;
701 alts[MRflush].c = x->flushc;
702 alts[MRflush].v = nil;
703 alts[MRflush].op = CHANRCV;
704 alts[NMR].op = CHANEND;
710 filsysrespond(x->fs, x, &fc, Edeleted);
720 n = sprint(buf, "%c%11d %11d %11d %11ld ", c, ms.xy.x, ms.xy.y, ms.buttons, ms.msec);
723 fc.count = min(n, cnt);
724 filsysrespond(x->fs, x, &fc, nil);
728 alts[MRdata].c = w->kbdread;
729 alts[MRdata].v = &krm;
730 alts[MRdata].op = CHANRCV;
731 alts[MRgone].c = w->gone;
732 alts[MRgone].v = nil;
733 alts[MRgone].op = CHANRCV;
734 alts[MRflush].c = x->flushc;
735 alts[MRflush].v = nil;
736 alts[MRflush].op = CHANRCV;
737 alts[NMR].op = CHANEND;
743 filsysrespond(x->fs, x, &fc, Edeleted);
753 fc.count = strlen(t)+1;
754 filsysrespond(x->fs, x, &fc, nil);
759 filsysrespond(x->fs, x, &fc, "cursor read not implemented");
762 /* The algorithm for snarf and text is expensive but easy and rarely used */
766 t = runetobyte(snarf, nsnarf, &n);
774 t = wcontents(w, &n);
786 filsysrespond(x->fs, x, &fc, nil);
796 n = sprint(buf, "%11d ", w->id);
804 filsysrespond(x->fs, x, &fc, "window has no name");
807 t = estrdup(w->name);
813 if(i == nil || Dx(r)<=0){
814 filsysrespond(x->fs, x, &fc, Enowindow);
825 n = sprint(buf, "%11s %11d %11d %11d %11d ",
826 chantostr(cbuf, i->chan),
827 r.min.x, r.min.y, r.max.x, r.max.y);
834 n = readwindow(i, t, r, off, cnt); /* careful; fc.count is unsigned */
837 errstr(buf, sizeof buf);
838 filsysrespond(x->fs, x, &fc, buf);
841 filsysrespond(x->fs, x, &fc, nil);
846 case Qwctl: /* read returns rectangle, hangs if not resized */
848 filsysrespond(x->fs, x, &fc, Etooshort);
852 alts[WCRdata].c = w->wctlread;
853 alts[WCRdata].v = &cwrm;
854 alts[WCRdata].op = CHANRCV;
855 alts[WCRgone].c = w->gone;
856 alts[WCRgone].v = nil;
857 alts[WCRgone].op = CHANRCV;
858 alts[WCRflush].c = x->flushc;
859 alts[WCRflush].v = nil;
860 alts[WCRflush].op = CHANRCV;
861 alts[NMR].op = CHANEND;
867 filsysrespond(x->fs, x, &fc, Edeleted);
877 t = malloc(cnt+1); /* be sure to have room for NUL */
886 filsysrespond(x->fs, x, &fc, nil);
891 fprint(2, "unknown qid %d in read\n", qid);
892 snprint(buf, sizeof(buf), "unknown qid in read");
893 filsysrespond(x->fs, x, &fc, buf);