Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | 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
#include <ctype.h>
14
 
15
char	Ebadwr[]		= "bad rectangle in wctl request";
16
char	Ewalloc[]		= "window allocation failed in wctl request";
17
 
18
/* >= Top are disallowed if mouse button is pressed */
19
enum
20
{
21
	New,
22
	Resize,
23
	Move,
24
	Scroll,
25
	Noscroll,
26
	Set,
27
	Top,
28
	Bottom,
29
	Current,
30
	Hide,
31
	Unhide,
32
	Delete,
33
};
34
 
35
static char *cmds[] = {
36
	[New]	= "new",
37
	[Resize]	= "resize",
38
	[Move]	= "move",
39
	[Scroll]	= "scroll",
40
	[Noscroll]	= "noscroll",
41
	[Set]		= "set",
42
	[Top]	= "top",
43
	[Bottom]	= "bottom",
44
	[Current]	= "current",
45
	[Hide]	= "hide",
46
	[Unhide]	= "unhide",
47
	[Delete]	= "delete",
48
	nil
49
};
50
 
51
enum
52
{
53
	Cd,
54
	Deltax,
55
	Deltay,
56
	Hidden,
57
	Id,
58
	Maxx,
59
	Maxy,
60
	Minx,
61
	Miny,
62
	PID,
63
	R,
64
	Scrolling,
65
	Noscrolling,
66
};
67
 
68
static char *params[] = {
69
	[Cd]	 			= "-cd",
70
	[Deltax]			= "-dx",
71
	[Deltay]			= "-dy",
72
	[Hidden]			= "-hide",
73
	[Id]				= "-id",
74
	[Maxx]			= "-maxx",
75
	[Maxy]			= "-maxy",
76
	[Minx]			= "-minx",
77
	[Miny]			= "-miny",
78
	[PID]				= "-pid",
79
	[R]				= "-r",
80
	[Scrolling]			= "-scroll",
81
	[Noscrolling]		= "-noscroll",
82
	nil
83
};
84
 
85
/*
86
 * Check that newly created window will be of manageable size
87
 */
88
int
89
goodrect(Rectangle r)
90
{
91
	if(!eqrect(canonrect(r), r))
92
		return 0;
93
	if(Dx(r)<100 || Dy(r)<3*font->height)
94
		return 0;
95
	/* must have some screen and border visible so we can move it out of the way */
96
	if(Dx(r) >= Dx(screen->r) && Dy(r) >= Dy(screen->r))
97
		return 0;
98
	/* reasonable sizes only please */
99
	if(Dx(r) > BIG*Dx(screen->r))
100
		return 0;
101
	if(Dy(r) > BIG*Dx(screen->r))
102
		return 0;
103
	return 1;
104
}
105
 
106
static
107
int
108
word(char **sp, char *tab[])
109
{
110
	char *s, *t;
111
	int i;
112
 
113
	s = *sp;
114
	while(isspace(*s))
115
		s++;
116
	t = s;
117
	while(*s!='\0' && !isspace(*s))
118
		s++;
119
	for(i=0; tab[i]!=nil; i++)
120
		if(strncmp(tab[i], t, strlen(tab[i])) == 0){
121
			*sp = s;
122
			return i;
123
	}
124
	return -1;
125
}
126
 
127
int
128
set(int sign, int neg, int abs, int pos)
129
{
130
	if(sign < 0)
131
		return neg;
132
	if(sign > 0)
133
		return pos;
134
	return abs;
135
}
136
 
137
Rectangle
138
newrect(void)
139
{
140
	static int i = 0;
141
	int minx, miny, dx, dy;
142
 
143
	dx = min(600, Dx(screen->r) - 2*Borderwidth);
144
	dy = min(400, Dy(screen->r) - 2*Borderwidth);
145
	minx = 32 + 16*i;
146
	miny = 32 + 16*i;
147
	i++;
148
	i %= 10;
149
 
150
	return Rect(minx, miny, minx+dx, miny+dy);
151
}
152
 
153
void
154
shift(int *minp, int *maxp, int min, int max)
155
{
156
	if(*minp < min){
157
		*maxp += min-*minp;
158
		*minp = min;
159
	}
160
	if(*maxp > max){
161
		*minp += max-*maxp;
162
		*maxp = max;
163
	}
164
}
165
 
166
Rectangle
167
rectonscreen(Rectangle r)
168
{
169
	shift(&r.min.x, &r.max.x, screen->r.min.x, screen->r.max.x);
170
	shift(&r.min.y, &r.max.y, screen->r.min.y, screen->r.max.y);
171
	return r;
172
}
173
 
174
/* permit square brackets, in the manner of %R */
175
int
176
riostrtol(char *s, char **t)
177
{
178
	int n;
179
 
180
	while(*s!='\0' && (*s==' ' || *s=='\t' || *s=='['))
181
		s++;
182
	if(*s == '[')
183
		s++;
184
	n = strtol(s, t, 10);
185
	if(*t != s)
186
		while((*t)[0] == ']')
187
			(*t)++;
188
	return n;
189
}
190
 
191
 
192
int
193
parsewctl(char **argp, Rectangle r, Rectangle *rp, int *pidp, int *idp, int *hiddenp, int *scrollingp, char **cdp, char *s, char *err)
194
{
195
	int cmd, param, xy, sign;
196
	char *t;
197
 
198
	*pidp = 0;
199
	*hiddenp = 0;
200
	*scrollingp = scrolling;
201
	*cdp = nil;
202
	cmd = word(&s, cmds);
203
	if(cmd < 0){
204
		strcpy(err, "unrecognized wctl command");
205
		return -1;
206
	}
207
	if(cmd == New)
208
		r = newrect();
209
 
210
	strcpy(err, "missing or bad wctl parameter");
211
	while((param = word(&s, params)) >= 0){
212
		switch(param){	/* special cases */
213
		case Hidden:
214
			*hiddenp = 1;
215
			continue;
216
		case Scrolling:
217
			*scrollingp = 1;
218
			continue;
219
		case Noscrolling:
220
			*scrollingp = 0;
221
			continue;
222
		case R:
223
			r.min.x = riostrtol(s, &t);
224
			if(t == s)
225
				return -1;
226
			s = t;
227
			r.min.y = riostrtol(s, &t);
228
			if(t == s)
229
				return -1;
230
			s = t;
231
			r.max.x = riostrtol(s, &t);
232
			if(t == s)
233
				return -1;
234
			s = t;
235
			r.max.y = riostrtol(s, &t);
236
			if(t == s)
237
				return -1;
238
			s = t;
239
			continue;
240
		}
241
		while(isspace(*s))
242
			s++;
243
		if(param == Cd){
244
			*cdp = s;
245
			while(*s && !isspace(*s))
246
				s++;
247
			if(*s != '\0')
248
				*s++ = '\0';
249
			continue;
250
		}
251
		sign = 0;
252
		if(*s == '-'){
253
			sign = -1;
254
			s++;
255
		}else if(*s == '+'){
256
			sign = +1;
257
			s++;
258
		}
259
		if(!isdigit(*s))
260
			return -1;
261
		xy = riostrtol(s, &s);
262
		switch(param){
263
		case -1:
264
			strcpy(err, "unrecognized wctl parameter");
265
			return -1;
266
		case Minx:
267
			r.min.x = set(sign, r.min.x-xy, xy, r.min.x+xy);
268
			break;
269
		case Miny:
270
			r.min.y = set(sign, r.min.y-xy, xy, r.min.y+xy);
271
			break;
272
		case Maxx:
273
			r.max.x = set(sign, r.max.x-xy, xy, r.max.x+xy);
274
			break;
275
		case Maxy:
276
			r.max.y = set(sign, r.max.y-xy, xy, r.max.y+xy);
277
			break;
278
		case Deltax:
279
			r.max.x = set(sign, r.max.x-xy, r.min.x+xy, r.max.x+xy);
280
			break;
281
		case Deltay:
282
			r.max.y = set(sign, r.max.y-xy, r.min.y+xy, r.max.y+xy);
283
			break;
284
		case Id:
285
			if(idp != nil)
286
				*idp = xy;
287
			break;
288
		case PID:
289
			if(pidp != nil)
290
				*pidp = xy;
291
			break;
292
		}
293
	}
294
 
295
	*rp = rectonscreen(rectaddpt(r, screen->r.min));
296
 
297
	while(isspace(*s))
298
		s++;
299
	if(cmd!=New && *s!='\0'){
300
		strcpy(err, "extraneous text in wctl message");
301
		return -1;
302
	}
303
 
304
	if(argp)
305
		*argp = s;
306
 
307
	return cmd;
308
}
309
 
310
int
311
wctlnew(Rectangle rect, char *arg, int pid, int hideit, int scrollit, char *dir, char *err)
312
{
313
	char **argv;
314
	Image *i;
315
 
316
	if(!goodrect(rect)){
317
		strcpy(err, Ebadwr);
318
		return -1;
319
	}
320
	argv = emalloc(4*sizeof(char*));
321
	argv[0] = "rc";
322
	argv[1] = "-c";
323
	while(isspace(*arg))
324
		arg++;
325
	if(*arg == '\0'){
326
		argv[1] = "-i";
327
		argv[2] = nil;
328
	}else{
329
		argv[2] = arg;
330
		argv[3] = nil;
331
	}
332
	if(hideit)
333
		i = allocimage(display, rect, screen->chan, 0, DWhite);
334
	else
335
		i = allocwindow(wscreen, rect, Refbackup, DWhite);
336
	if(i == nil){
337
		strcpy(err, Ewalloc);
338
		return -1;
339
	}
340
	border(i, rect, Selborder, red, ZP);
341
 
342
	new(i, hideit, scrollit, pid, dir, "/bin/rc", argv);
343
 
344
	free(argv);	/* when new() returns, argv and args have been copied */
345
	return 1;
346
}
347
 
348
int
349
writewctl(Xfid *x, char *err)
350
{
351
	int cnt, cmd, j, id, hideit, scrollit, pid;
352
	Image *i;
353
	char *arg, *dir;
354
	Rectangle rect;
355
	Window *w;
356
 
357
	w = x->f->w;
358
	cnt = x->count;
359
	x->data[cnt] = '\0';
360
	id = 0;
361
 
362
	rect = rectsubpt(w->screenr, screen->r.min);
363
	cmd = parsewctl(&arg, rect, &rect, &pid, &id, &hideit, &scrollit, &dir, x->data, err);
364
	if(cmd < 0)
365
		return -1;
366
 
367
	if(mouse->buttons!=0 && cmd>=Top){
368
		strcpy(err, "action disallowed when mouse active");
369
		return -1;
370
	}
371
 
372
	if(id != 0){
373
		for(j=0; j<nwindow; j++)
374
			if(window[j]->id == id)
375
				break;
376
		if(j == nwindow){
377
			strcpy(err, "no such window id");
378
			return -1;
379
		}
380
		w = window[j];
381
		if(w->deleted || w->i==nil){
382
			strcpy(err, "window deleted");
383
			return -1;
384
		}
385
	}
386
 
387
	switch(cmd){
388
	case New:
389
		return wctlnew(rect, arg, pid, hideit, scrollit, dir, err);
390
	case Set:
391
		if(pid > 0)
392
			wsetpid(w, pid, 0);
393
		return 1;
394
	case Move:
395
		rect = Rect(rect.min.x, rect.min.y, rect.min.x+Dx(w->screenr), rect.min.y+Dy(w->screenr));
396
		rect = rectonscreen(rect);
397
		/* fall through */
398
	case Resize:
399
		if(!goodrect(rect)){
400
			strcpy(err, Ebadwr);
401
			return -1;
402
		}
403
		if(eqrect(rect, w->screenr))
404
			return 1;
405
		i = allocwindow(wscreen, rect, Refbackup, DWhite);
406
		if(i == nil){
407
			strcpy(err, Ewalloc);
408
			return -1;
409
		}
410
		border(i, rect, Selborder, red, ZP);
411
		wsendctlmesg(w, Reshaped, i->r, i);
412
		return 1;
413
	case Scroll:
414
		w->scrolling = 1;
415
		wshow(w, w->nr);
416
		wsendctlmesg(w, Wakeup, ZR, nil);
417
		return 1;
418
	case Noscroll:
419
		w->scrolling = 0;
420
		wsendctlmesg(w, Wakeup, ZR, nil);
421
		return 1;
422
	case Top:
423
		wtopme(w);
424
		return 1;
425
	case Bottom:
426
		wbottomme(w);
427
		return 1;
428
	case Current:
429
		wcurrent(w);
430
		return 1;
431
	case Hide:
432
		switch(whide(w)){
433
		case -1:
434
			strcpy(err, "window already hidden");
435
			return -1;
436
		case 0:
437
			strcpy(err, "hide failed");
438
			return -1;
439
		default:
440
			break;
441
		}
442
		return 1;
443
	case Unhide:
444
		for(j=0; j<nhidden; j++)
445
			if(hidden[j] == w)
446
				break;
447
		if(j == nhidden){
448
			strcpy(err, "window not hidden");
449
			return -1;
450
		}
451
		if(wunhide(j) == 0){
452
			strcpy(err, "hide failed");
453
			return -1;
454
		}
455
		return 1;
456
	case Delete:
457
		wsendctlmesg(w, Deleted, ZR, nil);
458
		return 1;
459
	}
460
	strcpy(err, "invalid wctl message");
461
	return -1;
462
}
463
 
464
void
465
wctlthread(void *v)
466
{
467
	char *buf, *arg, *dir;
468
	int cmd, id, pid, hideit, scrollit;
469
	Rectangle rect;
470
	char err[ERRMAX];
471
	Channel *c;
472
 
473
	c = v;
474
 
475
	threadsetname("WCTLTHREAD");
476
 
477
	for(;;){
478
		buf = recvp(c);
479
		cmd = parsewctl(&arg, ZR, &rect, &pid, &id, &hideit, &scrollit, &dir, buf, err);
480
 
481
		switch(cmd){
482
		case New:
483
			wctlnew(rect, arg, pid, hideit, scrollit, dir, err);
484
		}
485
		free(buf);
486
	}
487
}
488
 
489
void
490
wctlproc(void *v)
491
{
492
	char *buf;
493
	int n, eofs;
494
	Channel *c;
495
 
496
	threadsetname("WCTLPROC");
497
	c = v;
498
 
499
	eofs = 0;
500
	for(;;){
501
		buf = emalloc(messagesize);
502
		n = read(wctlfd, buf, messagesize-1);	/* room for \0 */
503
		if(n < 0)
504
			break;
505
		if(n == 0){
506
			if(++eofs > 20)
507
				break;
508
			continue;
509
		}
510
		eofs = 0;
511
 
512
		buf[n] = '\0';
513
		sendp(c, buf);
514
	}
515
}