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);
104 threadsetname("xfid.%p", x);
108 x->flushtag = x->tag;
122 for(xf=xfid; xf; xf=xf->next)
123 if(xf->flushtag == x->oldtag){
124 incref(xf); /* to hold data structures up at tail of synchronization */
126 error("ref 1 in flush");
131 /* take over flushtag so follow up flushes wait for us */
132 x->flushtag = x->oldtag;
135 * wakeup filsysflush() in the filsysproc so the next
138 sendul(x->fs->csyncflush, 0);
141 enum { Done, Flush, End };
149 alts[Done].c = xf->c;
151 alts[Done].op = CHANSND;
152 alts[Flush].c = xf->flushc;
154 alts[Flush].op = CHANSND;
155 alts[End].op = CHANEND;
157 while(alt(alts) != Done)
160 if(nbrecv(x->flushc, nil)){
164 filsysrespond(x->fs, x, &t, nil);
171 int id, hideit, scrollit;
173 char *err, *n, *dir, errbuf[ERRMAX];
185 scrollit = scrolling;
187 if(x->aname[0] == 'N'){ /* N 100,100, 200, 200 - old syntax */
189 pid = strtoul(n, &n, 0);
192 r.min.x = strtoul(n, &n, 0);
195 r.min.y = strtoul(n, &n, 0);
198 r.max.x = strtoul(n, &n, 0);
201 r.max.y = strtoul(n, &n, 0);
207 i = allocimage(display, r, screen->chan, 0, DNofill);
209 i = allocwindow(wscreen, r, Refbackup, DNofill);
212 pid = -1; /* make sure we don't pop a shell! - UGH */
213 w = new(i, hideit, scrollit, pid, dir, nil, nil);
218 }else if(strncmp(x->aname, "new", 3) == 0){ /* new -dx -dy - new syntax, as in wctl */
220 if(parsewctl(nil, ZR, &r, &pid, nil, &hideit, &scrollit, &dir, x->aname, errbuf) < 0)
232 filsysrespond(x->fs, x, &t, err);
235 if(!newlymade) /* counteract dec() in winshell() */
238 filsysrespond(x->fs, x, &t, nil);
249 filsysrespond(x->fs, x, &t, Edeleted);
252 switch(FILE(x->f->qid)){
255 filsysrespond(x->fs, x, &t, Einuse);
262 filsysrespond(x->fs, x, &t, Einuse);
269 filsysrespond(x->fs, x, &t, Einuse);
273 * Reshaped: there's a race if the appl. opens the
274 * window, is resized, and then opens the mouse,
275 * but that's rare. The alternative is to generate
276 * a resized event every time a new program starts
277 * up in a window that has been resized since the
278 * dawn of time. We choose the lesser evil.
284 if(x->mode==ORDWR || x->mode==OWRITE)
288 if(x->mode==OREAD || x->mode==ORDWR){
290 * It would be much nicer to implement fan-out for wctl reads,
291 * so multiple people can see the resizings, but rio just isn't
292 * structured for that. It's structured for /dev/cons, which gives
293 * alternate data to alternate readers. So to keep things sane for
294 * wctl, we compromise and give an error if two people try to
295 * open it. Apologies.
298 filsysrespond(x->fs, x, &t, Einuse);
303 wsendctlmesg(w, Wakeup, ZR, nil);
308 t.iounit = messagesize-IOHDRSZ;
310 x->f->mode = x->mode;
311 filsysrespond(x->fs, x, &t, nil);
322 switch(FILE(x->f->qid)){
326 wsendctlmesg(w, Rawoff, ZR, nil);
330 wsendctlmesg(w, Holdoff, ZR, nil);
336 wsetcursor(w, FALSE);
343 w->mouseopen = FALSE;
345 wsendctlmesg(w, Refresh, w->i->r, nil);
347 /* odd behavior but really ok: replace snarf buffer when /dev/snarf is closed */
349 if(x->f->mode==ORDWR || x->f->mode==OWRITE){
350 snarf = runerealloc(snarf, ntsnarf+1);
351 cvttorunes(tsnarf, ntsnarf, snarf, &nb, &nsnarf, &nulls);
356 if(x->f->mode==OREAD || x->f->mode==ORDWR)
361 filsysrespond(x->fs, x, &t, nil);
368 int cnt, qid, nb, off, nr;
369 char err[ERRMAX], *p;
375 enum { CWdata, CWgone, CWflush, NCW };
380 filsysrespond(x->fs, x, &fc, Edeleted);
383 qid = FILE(x->f->qid);
389 alts[CWdata].c = w->conswrite;
390 alts[CWdata].v = &cwm;
391 alts[CWdata].op = CHANRCV;
392 alts[CWgone].c = w->gone;
393 alts[CWgone].v = nil;
394 alts[CWgone].op = CHANRCV;
395 alts[CWflush].c = x->flushc;
396 alts[CWflush].v = nil;
397 alts[CWflush].op = CHANRCV;
398 alts[NCW].op = CHANEND;
404 filsysrespond(x->fs, x, &fc, Edeleted);
413 memmove(x->data+nr, x->data, cnt); /* there's room: see malloc in filsysproc */
414 memmove(x->data, x->f->rpart, nr);
421 filsysrespond(x->fs, x, &fc, Enomem);
425 cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil);
426 /* approach end of buffer */
427 while(fullrune(x->data+nb, cnt-nb)){
428 nb += chartorune(&r[nr], x->data+nb);
433 memmove(x->f->rpart, x->data+nb, cnt-nb);
434 x->f->nrpart = cnt-nb;
441 filsysrespond(x->fs, x, &fc, nil);
445 if(strncmp(x->data, "holdon", 6)==0){
446 if(w->holding++ == 0)
447 wsendctlmesg(w, Holdon, ZR, nil);
450 if(strncmp(x->data, "holdoff", 7)==0 && w->holding){
451 if(--w->holding == 0)
452 wsendctlmesg(w, Holdoff, ZR, nil);
455 if(strncmp(x->data, "rawon", 5)==0){
458 wsendctlmesg(w, Holdoff, ZR, nil);
461 wsendctlmesg(w, Rawon, ZR, nil);
464 if(strncmp(x->data, "rawoff", 6)==0 && w->rawing){
466 wsendctlmesg(w, Rawoff, ZR, nil);
469 filsysrespond(x->fs, x, &fc, "unknown control message");
476 w->cursor.offset.x = BGLONG(x->data+0*4);
477 w->cursor.offset.y = BGLONG(x->data+1*4);
478 memmove(w->cursor.clr, x->data+2*4, 2*2*16);
479 w->cursorp = &w->cursor;
481 wsetcursor(w, !sweeping);
486 filsysrespond(x->fs, x, &fc, "non-zero offset writing label");
489 p = realloc(w->label, cnt+1);
491 filsysrespond(x->fs, x, &fc, Enomem);
496 memmove(w->label, x->data, cnt);
500 if(w!=input || Dx(w->screenr)<=0)
502 if(x->data[0] != 'm'){
503 filsysrespond(x->fs, x, &fc, Ebadmouse);
507 pt.x = strtoul(x->data+1, &p, 0);
509 filsysrespond(x->fs, x, &fc, Eshort);
512 pt.y = strtoul(p, nil, 0);
513 if(w==input && wpointto(mouse->xy)==w)
514 wsendctlmesg(w, Movemouse, Rpt(pt, pt), nil);
520 /* always append only */
521 if(ntsnarf > MAXSNARF){ /* avoid thrashing when people cut huge text */
522 filsysrespond(x->fs, x, &fc, Elong);
525 p = realloc(tsnarf, ntsnarf+cnt+1); /* room for NUL */
527 filsysrespond(x->fs, x, &fc, Enomem);
531 memmove(tsnarf+ntsnarf, x->data, cnt);
539 if(x->data[cnt-1] == '\n'){
542 x->data[cnt-1] = '\0';
544 /* assume data comes in a single write */
545 if(x->data[0] == '/'){
546 p = smprint("%.*s", cnt, x->data);
548 p = smprint("%s/%.*s", w->dir, cnt, x->data);
551 filsysrespond(x->fs, x, &fc, Enomem);
555 w->dir = cleanname(p);
559 if(writewctl(x, err) < 0){
560 filsysrespond(x->fs, x, &fc, err);
566 fprint(2, "unknown qid %d in write\n", qid);
567 filsysrespond(x->fs, x, &fc, "unknown qid in write");
571 filsysrespond(x->fs, x, &fc, nil);
575 readwindow(Image *i, char *t, Rectangle r, int offset, int n)
580 ww = bytesperline(r, i->depth);
581 r.min.y += offset/ww;
582 if(r.min.y >= r.max.y)
584 y = r.min.y + (n + ww-1)/ww;
589 if(oo == 0 && n >= m)
590 return unloadimage(i, r, (uchar*)t, n);
591 if((tt = malloc(m)) == nil)
593 m = unloadimage(i, r, tt, m) - oo;
596 memmove(t, tt + oo, m);
614 Channel *c1, *c2; /* chan (tuple(char*, int)) */
618 enum { Adata, Agone, Aflush, Aend };
623 filsysrespond(x->fs, x, &fc, Edeleted);
626 qid = FILE(x->f->qid);
632 filsysrespond(x->fs, x, &fc, Etooshort);
635 alts[Adata].c = w->wctlread;
639 alts[Adata].c = w->kbdread;
643 alts[Adata].c = w->consread;
646 alts[Adata].v = &crm;
647 alts[Adata].op = CHANRCV;
648 alts[Agone].c = w->gone;
650 alts[Agone].op = CHANRCV;
651 alts[Aflush].c = x->flushc;
652 alts[Aflush].v = nil;
653 alts[Aflush].op = CHANRCV;
654 alts[Aend].op = CHANEND;
660 filsysrespond(x->fs, x, &fc, Edeleted);
668 t = emalloc(cnt+UTFmax+1); /* room to unpack partial rune plus */
674 fc.count = min(cnt, pair.ns);
675 filsysrespond(x->fs, x, &fc, nil);
680 n = strlen(w->label);
685 fc.data = w->label+off;
687 filsysrespond(x->fs, x, &fc, nil);
691 alts[Adata].c = w->mouseread;
692 alts[Adata].v = &mrm;
693 alts[Adata].op = CHANRCV;
694 alts[Agone].c = w->gone;
696 alts[Agone].op = CHANRCV;
697 alts[Aflush].c = x->flushc;
698 alts[Aflush].v = nil;
699 alts[Aflush].op = CHANRCV;
700 alts[Aend].op = CHANEND;
706 filsysrespond(x->fs, x, &fc, Edeleted);
717 n = sprint(buf, "%c%11d %11d %11d %11ld ", c, ms.xy.x, ms.xy.y, ms.buttons, ms.msec);
720 fc.count = min(n, cnt);
721 filsysrespond(x->fs, x, &fc, nil);
725 filsysrespond(x->fs, x, &fc, "cursor read not implemented");
728 /* The algorithm for snarf and text is expensive but easy and rarely used */
732 t = runetobyte(snarf, nsnarf, &n);
740 t = wcontents(w, &n);
752 filsysrespond(x->fs, x, &fc, nil);
762 n = sprint(buf, "%11d ", w->id);
770 filsysrespond(x->fs, x, &fc, "window has no name");
773 t = estrdup(w->name);
779 filsysrespond(x->fs, x, &fc, Enowindow);
791 n = sprint(buf, "%11s %11d %11d %11d %11d ",
792 chantostr(cbuf, i->chan),
793 r.min.x, r.min.y, r.max.x, r.max.y);
802 n = readwindow(i, t, r, off, cnt); /* careful; fc.count is unsigned */
806 errstr(buf, sizeof buf);
807 filsysrespond(x->fs, x, &fc, buf);
810 filsysrespond(x->fs, x, &fc, nil);
816 fprint(2, "unknown qid %d in read\n", qid);
817 snprint(buf, sizeof(buf), "unknown qid in read");
818 filsysrespond(x->fs, x, &fc, buf);