14 char Einuse[] = "file in use";
15 char Edeleted[] = "window deleted";
16 char Etooshort[] = "buffer too small";
17 char Eshort[] = "short i/o request";
18 char Elong[] = "snarf buffer too long";
19 char Eunkid[] = "unknown id in attach";
20 char Ebadrect[] = "bad rectangle in attach";
21 char Ewindow[] = "cannot make window";
22 char Enowindow[] = "window has no image";
23 char Ebadmouse[] = "bad format on /dev/mouse";
28 static Xfid *xfidfree;
30 static Channel *cxfidalloc; /* chan(Xfid*) */
31 static Channel *cxfidfree; /* chan(Xfid*) */
37 xfidallocthread(void*)
40 enum { Alloc, Free, N };
43 alts[Alloc].c = cxfidalloc;
45 alts[Alloc].op = CHANRCV;
46 alts[Free].c = cxfidfree;
48 alts[Free].op = CHANRCV;
57 x = emalloc(sizeof(Xfid));
58 x->c = chancreate(sizeof(void(*)(Xfid*)), 0);
59 x->flushc = chancreate(sizeof(int), 0); /* notification only; no data */
63 threadcreate(xfidctl, x, 16384);
66 fprint(2, "%p incref %ld\n", x, x->ref);
70 error("flushtag in allocate");
76 fprint(2, "%p decref %ld\n", x, x->ref);
80 error("flushtag in free");
91 cxfidalloc = chancreate(sizeof(Xfid*), 0);
92 cxfidfree = chancreate(sizeof(Xfid*), 0);
93 threadcreate(xfidallocthread, nil, STACK);
105 snprint(buf, sizeof buf, "xfid.%p", x);
110 x->flushtag = x->tag;
124 for(xf=xfid; xf; xf=xf->next)
125 if(xf->flushtag == x->oldtag){
126 incref(xf); /* to hold data structures up at tail of synchronization */
128 error("ref 1 in flush");
133 /* take over flushtag so follow up flushes wait for us */
134 x->flushtag = x->oldtag;
137 * wakeup filsysflush() in the filsysproc so the next
140 sendul(x->fs->csyncflush, 0);
143 enum { Done, Flush, End };
151 alts[Done].c = xf->c;
153 alts[Done].op = CHANSND;
154 alts[Flush].c = xf->flushc;
156 alts[Flush].op = CHANSND;
157 alts[End].op = CHANEND;
159 while(alt(alts) != Done)
162 if(nbrecv(x->flushc, nil)){
166 filsysrespond(x->fs, x, &t, nil);
173 int id, hideit, scrollit;
175 char *err, *n, *dir, errbuf[ERRMAX];
186 scrollit = scrolling;
188 if(x->aname[0] == 'N'){ /* N 100,100, 200, 200 - old syntax */
190 pid = strtoul(n, &n, 0);
193 r.min.x = strtoul(n, &n, 0);
196 r.min.y = strtoul(n, &n, 0);
199 r.max.x = strtoul(n, &n, 0);
202 r.max.y = strtoul(n, &n, 0);
208 i = allocimage(display, r, screen->chan, 0, DNofill);
210 i = allocwindow(wscreen, r, Refbackup, DNofill);
213 pid = -1; /* make sure we don't pop a shell! - UGH */
214 w = new(i, hideit, scrollit, pid, nil, nil, nil);
219 }else if(strncmp(x->aname, "new", 3) == 0){ /* new -dx -dy - new syntax, as in wctl */
221 if(parsewctl(nil, ZR, &r, &pid, nil, &hideit, &scrollit, &dir, x->aname, errbuf) < 0)
233 filsysrespond(x->fs, x, &t, err);
236 if(!newlymade) /* counteract dec() in winshell() */
239 filsysrespond(x->fs, x, &t, nil);
250 filsysrespond(x->fs, x, &t, Edeleted);
253 switch(FILE(x->f->qid)){
256 filsysrespond(x->fs, x, &t, Einuse);
263 filsysrespond(x->fs, x, &t, Eperm);
269 filsysrespond(x->fs, x, &t, Einuse);
276 filsysrespond(x->fs, x, &t, Einuse);
280 * Reshaped: there's a race if the appl. opens the
281 * window, is resized, and then opens the mouse,
282 * but that's rare. The alternative is to generate
283 * a resized event every time a new program starts
284 * up in a window that has been resized since the
285 * dawn of time. We choose the lesser evil.
291 if(x->mode==ORDWR || x->mode==OWRITE)
295 if(x->mode==OREAD || x->mode==ORDWR){
297 * It would be much nicer to implement fan-out for wctl reads,
298 * so multiple people can see the resizings, but rio just isn't
299 * structured for that. It's structured for /dev/cons, which gives
300 * alternate data to alternate readers. So to keep things sane for
301 * wctl, we compromise and give an error if two people try to
302 * open it. Apologies.
305 filsysrespond(x->fs, x, &t, Einuse);
310 wsendctlmesg(w, Wakeup, ZR, nil);
315 t.iounit = messagesize-IOHDRSZ;
317 x->f->mode = x->mode;
318 filsysrespond(x->fs, x, &t, nil);
329 switch(FILE(x->f->qid)){
333 wsendctlmesg(w, Rawoff, ZR, nil);
337 wsendctlmesg(w, Holdoff, ZR, nil);
343 wsetcursor(w, FALSE);
350 w->mouseopen = FALSE;
352 wsendctlmesg(w, Refresh, w->i->r, nil);
354 /* odd behavior but really ok: replace snarf buffer when /dev/snarf is closed */
356 if(x->f->mode==ORDWR || x->f->mode==OWRITE){
357 snarf = runerealloc(snarf, ntsnarf+1);
358 cvttorunes(tsnarf, ntsnarf, snarf, &nb, &nsnarf, &nulls);
363 if(x->f->mode==OREAD || x->f->mode==ORDWR)
368 filsysrespond(x->fs, x, &t, nil);
375 int cnt, qid, nb, off, nr;
376 char err[ERRMAX], *p;
382 enum { CWdata, CWgone, CWflush, NCW };
387 filsysrespond(x->fs, x, &fc, Edeleted);
390 qid = FILE(x->f->qid);
396 alts[CWdata].c = w->conswrite;
397 alts[CWdata].v = &cwm;
398 alts[CWdata].op = CHANRCV;
399 alts[CWgone].c = w->gone;
400 alts[CWgone].v = nil;
401 alts[CWgone].op = CHANRCV;
402 alts[CWflush].c = x->flushc;
403 alts[CWflush].v = nil;
404 alts[CWflush].op = CHANRCV;
405 alts[NCW].op = CHANEND;
411 filsysrespond(x->fs, x, &fc, Edeleted);
420 memmove(x->data+nr, x->data, cnt); /* there's room: see malloc in filsysproc */
421 memmove(x->data, x->f->rpart, nr);
428 filsysrespond(x->fs, x, &fc, Enomem);
432 cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil);
433 /* approach end of buffer */
434 while(fullrune(x->data+nb, cnt-nb)){
435 nb += chartorune(&r[nr], x->data+nb);
440 memmove(x->f->rpart, x->data+nb, cnt-nb);
441 x->f->nrpart = cnt-nb;
448 filsysrespond(x->fs, x, &fc, nil);
452 if(strncmp(x->data, "holdon", 6)==0){
453 if(w->holding++ == 0)
454 wsendctlmesg(w, Holdon, ZR, nil);
457 if(strncmp(x->data, "holdoff", 7)==0 && w->holding){
458 if(--w->holding == 0)
459 wsendctlmesg(w, Holdoff, ZR, nil);
462 if(strncmp(x->data, "rawon", 5)==0){
465 wsendctlmesg(w, Holdoff, ZR, nil);
468 wsendctlmesg(w, Rawon, ZR, nil);
471 if(strncmp(x->data, "rawoff", 6)==0 && w->rawing){
473 wsendctlmesg(w, Rawoff, ZR, nil);
476 filsysrespond(x->fs, x, &fc, "unknown control message");
483 w->cursor.offset.x = BGLONG(x->data+0*4);
484 w->cursor.offset.y = BGLONG(x->data+1*4);
485 memmove(w->cursor.clr, x->data+2*4, 2*2*16);
486 w->cursorp = &w->cursor;
488 wsetcursor(w, !sweeping);
493 filsysrespond(x->fs, x, &fc, "non-zero offset writing label");
496 p = realloc(w->label, cnt+1);
498 filsysrespond(x->fs, x, &fc, Enomem);
503 memmove(w->label, x->data, cnt);
507 if(w!=input || Dx(w->screenr)<=0)
509 if(x->data[0] != 'm'){
510 filsysrespond(x->fs, x, &fc, Ebadmouse);
514 pt.x = strtoul(x->data+1, &p, 0);
516 filsysrespond(x->fs, x, &fc, Eshort);
519 pt.y = strtoul(p, nil, 0);
520 if(w==input && wpointto(mouse->xy)==w)
521 wsendctlmesg(w, Movemouse, Rpt(pt, pt), nil);
527 /* always append only */
528 if(ntsnarf > MAXSNARF){ /* avoid thrashing when people cut huge text */
529 filsysrespond(x->fs, x, &fc, Elong);
532 p = realloc(tsnarf, ntsnarf+cnt+1); /* room for NUL */
534 filsysrespond(x->fs, x, &fc, Enomem);
538 memmove(tsnarf+ntsnarf, x->data, cnt);
546 if(x->data[cnt-1] == '\n'){
549 x->data[cnt-1] = '\0';
551 /* assume data comes in a single write */
552 if(x->data[0] == '/'){
553 p = smprint("%.*s", cnt, x->data);
555 p = smprint("%s/%.*s", w->dir, cnt, x->data);
558 filsysrespond(x->fs, x, &fc, Enomem);
562 w->dir = cleanname(p);
566 keyboardsend(x->data, cnt);
570 if(writewctl(x, err) < 0){
571 filsysrespond(x->fs, x, &fc, err);
577 fprint(2, "unknown qid %d in write\n", qid);
578 filsysrespond(x->fs, x, &fc, "unknown qid in write");
582 filsysrespond(x->fs, x, &fc, nil);
586 readwindow(Image *i, char *t, Rectangle r, int offset, int n)
591 ww = bytesperline(r, i->depth);
592 r.min.y += offset/ww;
593 if(r.min.y >= r.max.y)
595 y = r.min.y + (n + ww-1)/ww;
600 if(oo == 0 && n >= m)
601 return unloadimage(i, r, (uchar*)t, n);
602 if((tt = malloc(m)) == nil)
604 m = unloadimage(i, r, tt, m) - oo;
607 memmove(t, tt + oo, m);
625 Channel *c1, *c2; /* chan (tuple(char*, int)) */
631 enum { CRdata, CRgone, CRflush, NCR };
632 enum { MRdata, MRgone, MRflush, NMR };
633 enum { WCRdata, WCRgone, WCRflush, NWCR };
638 filsysrespond(x->fs, x, &fc, Edeleted);
641 qid = FILE(x->f->qid);
646 alts[CRdata].c = w->consread;
647 alts[CRdata].v = &crm;
648 alts[CRdata].op = CHANRCV;
649 alts[CRgone].c = w->gone;
650 alts[CRgone].v = nil;
651 alts[CRgone].op = CHANRCV;
652 alts[CRflush].c = x->flushc;
653 alts[CRflush].v = nil;
654 alts[CRflush].op = CHANRCV;
655 alts[NCR].op = CHANEND;
661 filsysrespond(x->fs, x, &fc, Edeleted);
670 t = malloc(cnt+UTFmax+1); /* room to unpack partial rune plus */
677 filsysrespond(x->fs, x, &fc, nil);
682 n = strlen(w->label);
687 fc.data = w->label+off;
689 filsysrespond(x->fs, x, &fc, nil);
693 alts[MRdata].c = w->mouseread;
694 alts[MRdata].v = &mrm;
695 alts[MRdata].op = CHANRCV;
696 alts[MRgone].c = w->gone;
697 alts[MRgone].v = nil;
698 alts[MRgone].op = CHANRCV;
699 alts[MRflush].c = x->flushc;
700 alts[MRflush].v = nil;
701 alts[MRflush].op = CHANRCV;
702 alts[NMR].op = CHANEND;
708 filsysrespond(x->fs, x, &fc, Edeleted);
719 n = sprint(buf, "%c%11d %11d %11d %11ld ", c, ms.xy.x, ms.xy.y, ms.buttons, ms.msec);
722 fc.count = min(n, cnt);
723 filsysrespond(x->fs, x, &fc, nil);
727 alts[MRdata].c = w->kbdread;
728 alts[MRdata].v = &krm;
729 alts[MRdata].op = CHANRCV;
730 alts[MRgone].c = w->gone;
731 alts[MRgone].v = nil;
732 alts[MRgone].op = CHANRCV;
733 alts[MRflush].c = x->flushc;
734 alts[MRflush].v = nil;
735 alts[MRflush].op = CHANRCV;
736 alts[NMR].op = CHANEND;
742 filsysrespond(x->fs, x, &fc, Edeleted);
751 fc.count = strlen(t)+1;
752 filsysrespond(x->fs, x, &fc, nil);
757 filsysrespond(x->fs, x, &fc, "cursor read not implemented");
760 /* The algorithm for snarf and text is expensive but easy and rarely used */
764 t = runetobyte(snarf, nsnarf, &n);
772 t = wcontents(w, &n);
784 filsysrespond(x->fs, x, &fc, nil);
794 n = sprint(buf, "%11d ", w->id);
802 filsysrespond(x->fs, x, &fc, "window has no name");
805 t = estrdup(w->name);
811 if(i == nil || Dx(r)<=0){
812 filsysrespond(x->fs, x, &fc, Enowindow);
823 n = sprint(buf, "%11s %11d %11d %11d %11d ",
824 chantostr(cbuf, i->chan),
825 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 */
838 errstr(buf, sizeof buf);
839 filsysrespond(x->fs, x, &fc, buf);
842 filsysrespond(x->fs, x, &fc, nil);
847 case Qwctl: /* read returns rectangle, hangs if not resized */
849 filsysrespond(x->fs, x, &fc, Etooshort);
853 alts[WCRdata].c = w->wctlread;
854 alts[WCRdata].v = &cwrm;
855 alts[WCRdata].op = CHANRCV;
856 alts[WCRgone].c = w->gone;
857 alts[WCRgone].v = nil;
858 alts[WCRgone].op = CHANRCV;
859 alts[WCRflush].c = x->flushc;
860 alts[WCRflush].v = nil;
861 alts[WCRflush].op = CHANRCV;
862 alts[NWCR].op = CHANEND;
868 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);