Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_tlsv12/sys/src/cmd/rio/xfid.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <draw.h>
4
#include <thread.h>
5
#include <cursor.h>
6
#include <mouse.h>
7
#include <keyboard.h>
8
#include <frame.h>
9
#include <fcall.h>
10
#include <plumb.h>
11
#include "dat.h"
12
#include "fns.h"
13
 
14
#define	MAXSNARF	100*1024
15
 
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";
30
extern char Eperm[];
31
 
32
static	Xfid	*xfidfree;
33
static	Xfid	*xfid;
34
static	Channel	*cxfidalloc;	/* chan(Xfid*) */
35
static	Channel	*cxfidfree;	/* chan(Xfid*) */
36
 
37
static	char	*tsnarf;
38
static	int	ntsnarf;
39
 
40
void
41
xfidallocthread(void*)
42
{
43
	Xfid *x;
44
	enum { Alloc, Free, N };
45
	static Alt alts[N+1];
46
 
47
	alts[Alloc].c = cxfidalloc;
48
	alts[Alloc].v = nil;
49
	alts[Alloc].op = CHANRCV;
50
	alts[Free].c = cxfidfree;
51
	alts[Free].v = &x;
52
	alts[Free].op = CHANRCV;
53
	alts[N].op = CHANEND;
54
	for(;;){
55
		switch(alt(alts)){
56
		case Alloc:
57
			x = xfidfree;
58
			if(x)
59
				xfidfree = x->free;
60
			else{
61
				x = emalloc(sizeof(Xfid));
62
				x->c = chancreate(sizeof(void(*)(Xfid*)), 0);
63
				x->flushc = chancreate(sizeof(int), 0);	/* notification only; no data */
64
				x->flushtag = -1;
65
				x->next = xfid;
66
				xfid = x;
67
				threadcreate(xfidctl, x, 16384);
68
			}
69
			if(x->ref != 0){
70
				fprint(2, "%p incref %ld\n", x, x->ref);
71
				error("incref");
72
			}
73
			if(x->flushtag != -1)
74
				error("flushtag in allocate");
75
			incref(x);
76
			sendp(cxfidalloc, x);
77
			break;
78
		case Free:
79
			if(x->ref != 0){
80
				fprint(2, "%p decref %ld\n", x, x->ref);
81
				error("decref");
82
			}
83
			if(x->flushtag != -1)
84
				error("flushtag in free");
85
			x->free = xfidfree;
86
			xfidfree = x;
87
			break;
88
		}
89
	}
90
}
91
 
92
Channel*
93
xfidinit(void)
94
{
95
	cxfidalloc = chancreate(sizeof(Xfid*), 0);
96
	cxfidfree = chancreate(sizeof(Xfid*), 0);
97
	threadcreate(xfidallocthread, nil, STACK);
98
	return cxfidalloc;
99
}
100
 
101
void
102
xfidctl(void *arg)
103
{
104
	Xfid *x;
105
	void (*f)(Xfid*);
106
	char buf[64];
107
 
108
	x = arg;
109
	snprint(buf, sizeof buf, "xfid.%p", x);
110
	threadsetname(buf);
111
	for(;;){
112
		f = recvp(x->c);
113
		(*f)(x);
114
		if(decref(x) == 0)
115
			sendp(cxfidfree, x);
116
	}
117
}
118
 
119
void
120
xfidflush(Xfid *x)
121
{
122
	Fcall t;
123
	Xfid *xf;
124
 
125
	for(xf=xfid; xf; xf=xf->next)
126
		if(xf->flushtag == x->oldtag){
127
			xf->flushtag = -1;
128
			xf->flushing = TRUE;
129
			incref(xf);	/* to hold data structures up at tail of synchronization */
130
			if(xf->ref == 1)
131
				error("ref 1 in flush");
132
			if(canqlock(&xf->active)){
133
				qunlock(&xf->active);
134
				sendul(xf->flushc, 0);
135
			}else{
136
				qlock(&xf->active);	/* wait for him to finish */
137
				qunlock(&xf->active);
138
			}
139
			xf->flushing = FALSE;
140
			if(decref(xf) == 0)
141
				sendp(cxfidfree, xf);
142
			break;
143
		}
144
	filsysrespond(x->fs, x, &t, nil);
145
}
146
 
147
void
148
xfidattach(Xfid *x)
149
{
150
	Fcall t;
151
	int id, hideit, scrollit;
152
	Window *w;
153
	char *err, *n, *dir, errbuf[ERRMAX];
154
	int pid, newlymade;
155
	Rectangle r;
156
	Image *i;
157
 
158
	t.qid = x->f->qid;
159
	qlock(&all);
160
	w = nil;
161
	err = Eunkid;
162
	newlymade = FALSE;
163
	hideit = 0;
164
 
165
	if(x->aname[0] == 'N'){	/* N 100,100, 200, 200 - old syntax */
166
		n = x->aname+1;
167
		pid = strtoul(n, &n, 0);
168
		if(*n == ',')
169
			n++;
170
		r.min.x = strtoul(n, &n, 0);
171
		if(*n == ',')
172
			n++;
173
		r.min.y = strtoul(n, &n, 0);
174
		if(*n == ',')
175
			n++;
176
		r.max.x = strtoul(n, &n, 0);
177
		if(*n == ',')
178
			n++;
179
		r.max.y = strtoul(n, &n, 0);
180
  Allocate:
181
		if(!goodrect(r))
182
			err = Ebadrect;
183
		else{
184
			if(hideit)
185
				i = allocimage(display, r, screen->chan, 0, DWhite);
186
			else
187
				i = allocwindow(wscreen, r, Refbackup, DWhite);
188
			if(i){
189
				border(i, r, Selborder, display->black, ZP);
190
				if(pid == 0)
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);
194
				newlymade = TRUE;
195
			}else
196
				err = Ewindow;
197
		}
198
	}else if(strncmp(x->aname, "new", 3) == 0){	/* new -dx -dy - new syntax, as in wctl */
199
		pid = 0;
200
		if(parsewctl(nil, ZR, &r, &pid, nil, &hideit, &scrollit, &dir, x->aname, errbuf) < 0)
201
			err = errbuf;
202
		else
203
			goto Allocate;
204
	}else{
205
		id = atoi(x->aname);
206
		w = wlookid(id);
207
	}
208
	x->f->w = w;
209
	if(w == nil){
210
		qunlock(&all);
211
		x->f->busy = FALSE;
212
		filsysrespond(x->fs, x, &t, err);
213
		return;
214
	}
215
	if(!newlymade)	/* counteract dec() in winshell() */
216
		incref(w);
217
	qunlock(&all);
218
	filsysrespond(x->fs, x, &t, nil);
219
}
220
 
221
void
222
xfidopen(Xfid *x)
223
{
224
	Fcall t;
225
	Window *w;
226
 
227
	w = x->f->w;
228
	if(w->deleted){
229
		filsysrespond(x->fs, x, &t, Edeleted);
230
		return;
231
	}
232
	switch(FILE(x->f->qid)){
233
	case Qconsctl:
234
		if(w->ctlopen){
235
			filsysrespond(x->fs, x, &t, Einuse);
236
			return;
237
		}
238
		w->ctlopen = TRUE;
239
		break;
240
	case Qkbdin:
241
		if(w !=  wkeyboard){
242
			filsysrespond(x->fs, x, &t, Eperm);
243
			return;
244
		}
245
		break;
246
	case Qmouse:
247
		if(w->mouseopen){
248
			filsysrespond(x->fs, x, &t, Einuse);
249
			return;
250
		}
251
		/*
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.
258
		 */
259
		w->resized = FALSE;
260
		w->mouseopen = TRUE;
261
		break;
262
	case Qsnarf:
263
		if(x->mode==ORDWR || x->mode==OWRITE){
264
			if(tsnarf)
265
				free(tsnarf);	/* collision, but OK */
266
			ntsnarf = 0;
267
			tsnarf = malloc(1);
268
		}
269
		break;
270
	case Qwctl:
271
		if(x->mode==OREAD || x->mode==ORDWR){
272
			/*
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.
279
			 */
280
			if(w->wctlopen){
281
				filsysrespond(x->fs, x, &t, Einuse);
282
				return;
283
			}
284
			w->wctlopen = TRUE;
285
			w->wctlready = 1;
286
			wsendctlmesg(w, Wakeup, ZR, nil);
287
		}
288
		break;
289
	}
290
	t.qid = x->f->qid;
291
	t.iounit = messagesize-IOHDRSZ;
292
	x->f->open = TRUE;
293
	x->f->mode = x->mode;
294
	filsysrespond(x->fs, x, &t, nil);
295
}
296
 
297
void
298
xfidclose(Xfid *x)
299
{
300
	Fcall t;
301
	Window *w;
302
	int nb, nulls;
303
 
304
	w = x->f->w;
305
	switch(FILE(x->f->qid)){
306
	case Qconsctl:
307
		if(w->rawing){
308
			w->rawing = FALSE;
309
			wsendctlmesg(w, Rawoff, ZR, nil);
310
		}
311
		if(w->holding){
312
			w->holding = FALSE;
313
			wsendctlmesg(w, Holdoff, ZR, nil);
314
		}
315
		w->ctlopen = FALSE;
316
		break;
317
	case Qcursor:
318
		w->cursorp = nil;
319
		wsetcursor(w, FALSE);
320
		break;
321
	case Qmouse:
322
		w->resized = FALSE;
323
		w->mouseopen = FALSE;
324
		if(w->i != nil)
325
			wsendctlmesg(w, Refresh, w->i->r, nil);
326
		break;
327
	/* odd behavior but really ok: replace snarf buffer when /dev/snarf is closed */
328
	case Qsnarf:
329
		if(x->f->mode==ORDWR || x->f->mode==OWRITE){
330
			snarf = runerealloc(snarf, ntsnarf+1);
331
			cvttorunes(tsnarf, ntsnarf, snarf, &nb, &nsnarf, &nulls);
332
			free(tsnarf);
333
			tsnarf = nil;
334
			ntsnarf = 0;
335
		}
336
		break;
337
	case Qwctl:
338
		if(x->f->mode==OREAD || x->f->mode==ORDWR)
339
			w->wctlopen = FALSE;
340
		break;
341
	}
342
	wclose(w);
343
	filsysrespond(x->fs, x, &t, nil);
344
}
345
 
346
void
347
xfidwrite(Xfid *x)
348
{
349
	Fcall fc;
350
	int c, cnt, qid, nb, off, nr;
351
	char buf[256], *p;
352
	Point pt;
353
	Window *w;
354
	Rune *r;
355
	Conswritemesg cwm;
356
	Stringpair pair;
357
	enum { CWdata, CWflush, NCW };
358
	Alt alts[NCW+1];
359
 
360
	w = x->f->w;
361
	if(w->deleted){
362
		filsysrespond(x->fs, x, &fc, Edeleted);
363
		return;
364
	}
365
	qid = FILE(x->f->qid);
366
	cnt = x->count;
367
	off = x->offset;
368
	x->data[cnt] = 0;
369
	switch(qid){
370
	case Qcons:
371
		nr = x->f->nrpart;
372
		if(nr > 0){
373
			memmove(x->data+nr, x->data, cnt);	/* there's room: see malloc in filsysproc */
374
			memmove(x->data, x->f->rpart, nr);
375
			cnt += nr;
376
			x->f->nrpart = 0;
377
		}
378
		r = runemalloc(cnt);
379
		cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil);
380
		/* approach end of buffer */
381
		while(fullrune(x->data+nb, cnt-nb)){
382
			c = nb;
383
			nb += chartorune(&r[nr], x->data+c);
384
			if(r[nr])
385
				nr++;
386
		}
387
		if(nb < cnt){
388
			memmove(x->f->rpart, x->data+nb, cnt-nb);
389
			x->f->nrpart = cnt-nb;
390
		}
391
		x->flushtag = x->tag;
392
 
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;
400
 
401
		switch(alt(alts)){
402
		case CWdata:
403
			break;
404
		case CWflush:
405
			filsyscancel(x);
406
			return;
407
		}
408
 
409
		/* received data */
410
		x->flushtag = -1;
411
		if(x->flushing){
412
			recv(x->flushc, nil);	/* wake up flushing xfid */
413
			pair.s = runemalloc(1);
414
			pair.ns = 0;
415
			send(cwm.cw, &pair);		/* wake up window with empty data */
416
			filsyscancel(x);
417
			return;
418
		}
419
		qlock(&x->active);
420
		pair.s = r;
421
		pair.ns = nr;
422
		send(cwm.cw, &pair);
423
		fc.count = x->count;
424
		filsysrespond(x->fs, x, &fc, nil);
425
		qunlock(&x->active);
426
		return;
427
 
428
	case Qconsctl:
429
		if(strncmp(x->data, "holdon", 6)==0){
430
			if(w->holding++ == 0)
431
				wsendctlmesg(w, Holdon, ZR, nil);
432
			break;
433
		}
434
		if(strncmp(x->data, "holdoff", 7)==0 && w->holding){
435
			if(--w->holding == FALSE)
436
				wsendctlmesg(w, Holdoff, ZR, nil);
437
			break;
438
		}
439
		if(strncmp(x->data, "rawon", 5)==0){
440
			if(w->holding){
441
				w->holding = FALSE;
442
				wsendctlmesg(w, Holdoff, ZR, nil);
443
			}
444
			if(w->rawing++ == 0)
445
				wsendctlmesg(w, Rawon, ZR, nil);
446
			break;
447
		}
448
		if(strncmp(x->data, "rawoff", 6)==0 && w->rawing){
449
			if(--w->rawing == 0)
450
				wsendctlmesg(w, Rawoff, ZR, nil);
451
			break;
452
		}
453
		filsysrespond(x->fs, x, &fc, "unknown control message");
454
		return;
455
 
456
	case Qcursor:
457
		if(cnt < 2*4+2*2*16)
458
			w->cursorp = nil;
459
		else{
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;
464
		}
465
		wsetcursor(w, !sweeping);
466
		break;
467
 
468
	case Qlabel:
469
		if(off != 0){
470
			filsysrespond(x->fs, x, &fc, "non-zero offset writing label");
471
			return;
472
		}
473
		free(w->label);
474
		w->label = emalloc(cnt+1);
475
		memmove(w->label, x->data, cnt);
476
		w->label[cnt] = 0;
477
		break;
478
 
479
	case Qmouse:
480
		if(w!=input || Dx(w->screenr)<=0)
481
			break;
482
		if(x->data[0] != 'm'){
483
			filsysrespond(x->fs, x, &fc, Ebadmouse);
484
			return;
485
		}
486
		p = nil;
487
		pt.x = strtoul(x->data+1, &p, 0);
488
		if(p == nil){
489
			filsysrespond(x->fs, x, &fc, Eshort);
490
			return;
491
		}
492
		pt.y = strtoul(p, nil, 0);
493
		if(w==input && wpointto(mouse->xy)==w)
494
			wsendctlmesg(w, Movemouse, Rpt(pt, pt), nil);
495
		break;
496
 
497
	case Qsnarf:
498
		/* always append only */
499
		if(ntsnarf > MAXSNARF){	/* avoid thrashing when people cut huge text */
500
			filsysrespond(x->fs, x, &fc, Elong);
501
			return;
502
		}
503
		tsnarf = erealloc(tsnarf, ntsnarf+cnt+1);	/* room for NUL */
504
		memmove(tsnarf+ntsnarf, x->data, cnt);
505
		ntsnarf += cnt;
506
		snarfversion++;
507
		break;
508
 
509
	case Qwdir:
510
		if(cnt == 0)
511
			break;
512
		if(x->data[cnt-1] == '\n'){
513
			if(cnt == 1)
514
				break;
515
			x->data[cnt-1] = '\0';
516
		}
517
		/* assume data comes in a single write */
518
		/*
519
		  * Problem: programs like dossrv, ftp produce illegal UTF;
520
		  * we must cope by converting it first.
521
		  */
522
		snprint(buf, sizeof buf, "%.*s", cnt, x->data);
523
		if(buf[0] == '/'){
524
			free(w->dir);
525
			w->dir = estrdup(buf);
526
		}else{
527
			p = emalloc(strlen(w->dir) + 1 + strlen(buf) + 1);
528
			sprint(p, "%s/%s", w->dir, buf);
529
			free(w->dir);
530
			w->dir = cleanname(p);
531
		}
532
		break;
533
 
534
	case Qkbdin:
535
		keyboardsend(x->data, cnt);
536
		break;
537
 
538
	case Qwctl:
539
		if(writewctl(x, buf) < 0){
540
			filsysrespond(x->fs, x, &fc, buf);
541
			return;
542
		}
543
		flushimage(display, 1);
544
		break;
545
 
546
	default:
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);
550
		return;
551
	}
552
	fc.count = cnt;
553
	filsysrespond(x->fs, x, &fc, nil);
554
}
555
 
556
int
557
readwindow(Image *i, char *t, Rectangle r, int offset, int n)
558
{
559
	int ww, y;
560
 
561
	offset -= 5*12;
562
	ww = bytesperline(r, screen->depth);
563
	r.min.y += offset/ww;
564
	if(r.min.y >= r.max.y)
565
		return 0;
566
	y = r.min.y + n/ww;
567
	if(y < r.max.y)
568
		r.max.y = y;
569
	if(r.max.y <= r.min.y)
570
		return 0;
571
	return unloadimage(i, r, (uchar*)t, n);
572
}
573
 
574
void
575
xfidread(Xfid *x)
576
{
577
	Fcall fc;
578
	int n, off, cnt, c;
579
	uint qid;
580
	char buf[128], *t;
581
	char cbuf[30];
582
	Window *w;
583
	Mouse ms;
584
	Rectangle r;
585
	Image *i;
586
	Channel *c1, *c2;	/* chan (tuple(char*, int)) */
587
	Consreadmesg crm;
588
	Mousereadmesg mrm;
589
	Consreadmesg cwrm;
590
	Stringpair pair;
591
	enum { CRdata, CRflush, NCR };
592
	enum { MRdata, MRflush, NMR };
593
	enum { WCRdata, WCRflush, NWCR };
594
	Alt alts[NCR+1];
595
 
596
	w = x->f->w;
597
	if(w->deleted){
598
		filsysrespond(x->fs, x, &fc, Edeleted);
599
		return;
600
	}
601
	qid = FILE(x->f->qid);
602
	off = x->offset;
603
	cnt = x->count;
604
	switch(qid){
605
	case Qcons:
606
		x->flushtag = x->tag;
607
 
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;
615
 
616
		switch(alt(alts)){
617
		case CRdata:
618
			break;
619
		case CRflush:
620
			filsyscancel(x);
621
			return;
622
		}
623
 
624
		/* received data */
625
		x->flushtag = -1;
626
		c1 = crm.c1;
627
		c2 = crm.c2;
628
		t = malloc(cnt+UTFmax+1);	/* room to unpack partial rune plus */
629
		pair.s = t;
630
		pair.ns = cnt;
631
		send(c1, &pair);
632
		if(x->flushing){
633
			recv(x->flushc, nil);	/* wake up flushing xfid */
634
			recv(c2, nil);			/* wake up window and toss data */
635
			free(t);
636
			filsyscancel(x);
637
			return;
638
		}
639
		qlock(&x->active);
640
		recv(c2, &pair);
641
		fc.data = pair.s;
642
		fc.count = pair.ns;
643
		filsysrespond(x->fs, x, &fc, nil);
644
		free(t);
645
		qunlock(&x->active);
646
		break;
647
 
648
	case Qlabel:
649
		n = strlen(w->label);
650
		if(off > n)
651
			off = n;
652
		if(off+cnt > n)
653
			cnt = n-off;
654
		fc.data = w->label+off;
655
		fc.count = cnt;
656
		filsysrespond(x->fs, x, &fc, nil);
657
		break;
658
 
659
	case Qmouse:
660
		x->flushtag = x->tag;
661
 
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;
669
 
670
		switch(alt(alts)){
671
		case MRdata:
672
			break;
673
		case MRflush:
674
			filsyscancel(x);
675
			return;
676
		}
677
 
678
		/* received data */
679
		x->flushtag = -1;
680
		if(x->flushing){
681
			recv(x->flushc, nil);		/* wake up flushing xfid */
682
			recv(mrm.cm, nil);			/* wake up window and toss data */
683
			filsyscancel(x);
684
			return;
685
		}
686
		qlock(&x->active);
687
		recv(mrm.cm, &ms);
688
		c = 'm';
689
		if(w->resized)
690
			c = 'r';
691
		n = sprint(buf, "%c%11d %11d %11d %11ld ", c, ms.xy.x, ms.xy.y, ms.buttons, ms.msec);
692
		w->resized = 0;
693
		fc.data = buf;
694
		fc.count = min(n, cnt);
695
		filsysrespond(x->fs, x, &fc, nil);
696
		qunlock(&x->active);
697
		break;
698
 
699
	case Qcursor:
700
		filsysrespond(x->fs, x, &fc, "cursor read not implemented");
701
		break;
702
 
703
	/* The algorithm for snarf and text is expensive but easy and rarely used */
704
	case Qsnarf:
705
		getsnarf();
706
		if(nsnarf)
707
			t = runetobyte(snarf, nsnarf, &n);
708
		else {
709
			t = nil;
710
			n = 0;
711
		}
712
		goto Text;
713
 
714
	case Qtext:
715
		t = wcontents(w, &n);
716
		goto Text;
717
 
718
	Text:
719
		if(off > n){
720
			off = n;
721
			cnt = 0;
722
		}
723
		if(off+cnt > n)
724
			cnt = n-off;
725
		fc.data = t+off;
726
		fc.count = cnt;
727
		filsysrespond(x->fs, x, &fc, nil);
728
		free(t);
729
		break;
730
 
731
	case Qwdir:
732
		t = estrdup(w->dir);
733
		n = strlen(t);
734
		goto Text;
735
 
736
	case Qwinid:
737
		n = sprint(buf, "%11d ", w->id);
738
		t = estrdup(buf);
739
		goto Text;
740
 
741
 
742
	case Qwinname:
743
		n = strlen(w->name);
744
		if(n == 0){
745
			filsysrespond(x->fs, x, &fc, "window has no name");
746
			break;
747
		}
748
		t = estrdup(w->name);
749
		goto Text;
750
 
751
	case Qwindow:
752
		i = w->i;
753
		if(i == nil || Dx(w->screenr)<=0){
754
			filsysrespond(x->fs, x, &fc, Enowindow);
755
			return;
756
		}
757
		r = w->screenr;
758
		goto caseImage;
759
 
760
	case Qscreen:
761
		i = display->image;
762
		if(i == nil){
763
			filsysrespond(x->fs, x, &fc, "no top-level screen");
764
			break;
765
		}
766
		r = i->r;
767
		/* fall through */
768
 
769
	caseImage:
770
		if(off < 5*12){
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);
774
			t = estrdup(buf);
775
			goto Text;
776
		}
777
		t = malloc(cnt);
778
		fc.data = t;
779
		n = readwindow(i, t, r, off, cnt);	/* careful; fc.count is unsigned */
780
		if(n < 0){
781
			buf[0] = 0;
782
			errstr(buf, sizeof buf);
783
			filsysrespond(x->fs, x, &fc, buf);
784
		}else{
785
			fc.count = n;
786
			filsysrespond(x->fs, x, &fc, nil);
787
		}
788
		free(t);
789
		return;
790
 
791
	case Qwctl:	/* read returns rectangle, hangs if not resized */
792
		if(cnt < 4*12){
793
			filsysrespond(x->fs, x, &fc, Etooshort);
794
			break;
795
		}
796
		x->flushtag = x->tag;
797
 
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;
805
 
806
		switch(alt(alts)){
807
		case WCRdata:
808
			break;
809
		case WCRflush:
810
			filsyscancel(x);
811
			return;
812
		}
813
 
814
		/* received data */
815
		x->flushtag = -1;
816
		c1 = cwrm.c1;
817
		c2 = cwrm.c2;
818
		t = malloc(cnt+1);	/* be sure to have room for NUL */
819
		pair.s = t;
820
		pair.ns = cnt+1;
821
		send(c1, &pair);
822
		if(x->flushing){
823
			recv(x->flushc, nil);	/* wake up flushing xfid */
824
			recv(c2, nil);			/* wake up window and toss data */
825
			free(t);
826
			filsyscancel(x);
827
			return;
828
		}
829
		qlock(&x->active);
830
		recv(c2, &pair);
831
		fc.data = pair.s;
832
		if(pair.ns > cnt)
833
			pair.ns = cnt;
834
		fc.count = pair.ns;
835
		filsysrespond(x->fs, x, &fc, nil);
836
		free(t);
837
		qunlock(&x->active);
838
		break;
839
 
840
	default:
841
		fprint(2, "unknown qid %d in read\n", qid);
842
		sprint(buf, "unknown qid in read");
843
		filsysrespond(x->fs, x, &fc, buf);
844
		break;
845
	}
846
}