Example #1
0
void
area_moveto(Area *to, Frame *f) {
	Area *from;

	assert(to->view == f->view);

	if(f->client->fullscreen >= 0 && !to->floating)
		return;

	from = f->area;
	if(from == to)
		return;

	area_detach(f);

	if(from->floating ^ to->floating)
		event("ArrangeView\n");

	/* Temporary kludge. */
	if(!to->floating
	&& to->floating != from->floating
	&& !eqrect(f->colr, ZR))
		column_attachrect(to, f, f->colr);
	else
		area_attach(to, f);
}
Example #2
0
File: windw.c Project: 8l/inferno
/*
 * return non-zero if the window size has changed (XXX choose better return value/function name!)
 */
int
tkupdatewinsize(Tk *tk)
{
	TkWin *tkw;
	Image *previ;
	Rectangle r, or;
	int bw2;

	tkw = TKobj(TkWin, tk);
	bw2 = 2*tk->borderwidth;
	r.min.x = tkw->req.x;
	r.min.y = tkw->req.y;
	r.max.x = r.min.x + tk->act.width + bw2;
	r.max.y = r.min.y + tk->act.height + bw2;
	previ = tkw->image;
	if(previ != nil){
		or.min.x = tkw->act.x;
		or.min.y = tkw->act.y;
		or.max.x = tkw->act.x + Dx(previ->r);
		or.max.y = tkw->act.y + Dy(previ->r);
		if(eqrect(or, r))
			return 0;
	}
	tkexterncreatewin(tk, r);
	return 1;
}
Example #3
0
File: root.c Project: bartman/wmii
static void
motion_event(Window *w, XMotionEvent *e) {
	Rectangle r, r2;

	r = rectsetorigin(Rect(0, 0, 1, 1), Pt(e->x_root, e->y_root));
	r2 = constrain(r, 0);
	if(!eqrect(r, r2))
		warppointer(r2.min);
}
Example #4
0
void
iconinit(void)
{
	Rectangle r;
	Image *tmp;

	if(tagcols[BACK] == nil) {
		/* Blue */
		tagcols[BACK] = allocimagemix(display, DPalebluegreen, DWhite);
		tagcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalegreygreen);
		tagcols[BORD] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue);
		tagcols[TEXT] = display->black;
		tagcols[HTEXT] = display->black;
	
		/* Yellow */
		textcols[BACK] = allocimagemix(display, DPaleyellow, DWhite);
		textcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkyellow);
		textcols[BORD] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DYellowgreen);
		textcols[TEXT] = display->black;
		textcols[HTEXT] = display->black;
	}
	
	r = Rect(0, 0, Scrollwid+ButtonBorder, font->height+1);
	if(button && eqrect(r, button->r))
		return;

	if(button){
		freeimage(button);
		freeimage(modbutton);
		freeimage(colbutton);
	}

	button = allocimage(display, r, screen->chan, 0, DNofill);
	draw(button, r, tagcols[BACK], nil, r.min);
	r.max.x -= ButtonBorder;
	border(button, r, ButtonBorder, tagcols[BORD], ZP);

	r = button->r;
	modbutton = allocimage(display, r, screen->chan, 0, DNofill);
	draw(modbutton, r, tagcols[BACK], nil, r.min);
	r.max.x -= ButtonBorder;
	border(modbutton, r, ButtonBorder, tagcols[BORD], ZP);
	r = insetrect(r, ButtonBorder);
	tmp = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DMedblue);
	draw(modbutton, r, tmp, nil, ZP);
	freeimage(tmp);

	r = button->r;
	colbutton = allocimage(display, r, screen->chan, 0, DPurpleblue);

	but2col = allocimage(display, r, screen->chan, 1, 0xAA0000FF);
	but3col = allocimage(display, r, screen->chan, 1, 0x006600FF);
}
Example #5
0
File: windw.c Project: 8l/inferno
char*
tkseecmd(TkTop *t, char *arg, char **ret)
{
	TkOptab tko[2];
	TkSee opts;
	TkName *names;
	Tk *tk;
	char *e;
	Rectangle vr;
	Point vp;

	opts.r[0] = bbnil.min.x;
	opts.r[1] = bbnil.min.y;
	opts.r[2] = bbnil.max.x;
	opts.r[3] = bbnil.max.y;
	opts.p[0] = bbnil.max.x;
	opts.p[1] = bbnil.max.y;
	opts.query = 0;

	tko[0].ptr = &opts;
	tko[0].optab = seeopts;
	tko[1].ptr = nil;
	names = nil;
	e = tkparse(t, arg, tko, &names);
	if (e != nil)
		return e;
	if (names == nil)
		return TkBadwp;
	tk = tklook(t, names->name, 0);
	tkfreename(names);
	if (tk == nil)
		return TkBadwp;
	if (opts.query) {
		if (!tkvisiblerect(tk, &vr))
			return nil;
		/* XXX should this be converted into screen coords? */
		return tkvalue(ret, "%d %d %d %d", vr.min.x, vr.min.y, vr.max.x, vr.max.y);
	}
	vr.min.x = opts.r[0];
	vr.min.y = opts.r[1];
	vr.max.x = opts.r[2];
	vr.max.y = opts.r[3];
	vp.x = opts.p[0];
	vp.y = opts.p[1];

	if (eqrect(vr, bbnil))
		vr = tkrect(tk, 1);
	if (eqpt(vp, bbnil.max))
		vp = vr.min;
	tksee(tk, vr, vp);
	return nil;
}
Example #6
0
void
redraw(Image *screen)
{
	static int tm, ntm;
	static Rectangle r;
	static Point c;
	static int rad;
	static Image *im;
	int i;
	int anghr, angmin;
	static Tm tms;
	static Tm ntms;

	ntm = time(0);
	if(ntm == tm && eqrect(screen->r, r))
		return;

	ntms = *localtime(ntm);
	anghr = 90-(ntms.hour*5 + ntms.min/12)*6;
	angmin = 90-ntms.min*6;
	tm = ntm;
	tms = ntms;
	r = screen->r;
	c = divpt(addpt(r.min, r.max), 2);
	rad = Dx(r) < Dy(r) ? Dx(r) : Dy(r);
	rad /= 2;
	rad -= 8;

	draw(screen, screen->r, back, nil, ZP);
	for(i=0; i<12; i++)
		fillellipse(screen, circlept(c, rad, i*(360/12)), 2, 2, dots, ZP);

	line(screen, c, circlept(c, (rad*3)/4, angmin), 0, 0, 1, minhand, ZP);
	line(screen, c, circlept(c, rad/2, anghr), 0, 0, 1, hrhand, ZP);

	flushimage(display, 1);
}
Example #7
0
int
eenter(char *ask, char *buf, int len, Mouse *m)
{
	int done, down, tick, n, h, w, l, i;
	Image *b, *save, *backcol, *bordcol;
	Point p, o, t;
	Rectangle r, sc;
	Event ev;
	Rune k;

	o = screen->r.min;
	backcol = allocimagemix(display, DPurpleblue, DWhite);
	bordcol = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue);
	if(backcol == nil || bordcol == nil)
		return -1;

	while(ecankbd())
		ekbd();

	if(m) o = m->xy;

	if(buf && len > 0)
		n = strlen(buf);
	else {
		buf = nil;
		len = 0;
		n = 0;
	}

	k = -1;
	tick = n;
	save = nil;
	done = down = 0;

	p = stringsize(font, " ");
	h = p.y;
	w = p.x;

	b = screen;
	sc = b->clipr;
	replclipr(b, 0, b->r);

	while(!done){
		p = stringsize(font, buf ? buf : "");
		if(ask && ask[0]){
			if(buf) p.x += w;
			p.x += stringwidth(font, ask);
		}
		r = rectaddpt(insetrect(Rpt(ZP, p), -4), o);
		p.x = 0;
		r = rectsubpt(r, p);

		p = ZP;
		if(r.min.x < screen->r.min.x)
			p.x = screen->r.min.x - r.min.x;
		if(r.min.y < screen->r.min.y)
			p.y = screen->r.min.y - r.min.y;
		r = rectaddpt(r, p);
		p = ZP;
		if(r.max.x > screen->r.max.x)
			p.x = r.max.x - screen->r.max.x;
		if(r.max.y > screen->r.max.y)
			p.y = r.max.y - screen->r.max.y;
		r = rectsubpt(r, p);

		r = insetrect(r, -2);
		if(save == nil){
			save = allocimage(display, r, b->chan, 0, DNofill);
			if(save == nil){
				n = -1;
				break;
			}
			draw(save, r, b, nil, r.min);
		}
		draw(b, r, backcol, nil, ZP);
		border(b, r, 2, bordcol, ZP);
		p = addpt(r.min, Pt(6, 6));
		if(ask && ask[0]){
			p = string(b, p, bordcol, ZP, font, ask);
			if(buf) p.x += w;
		}
		if(buf){
			t = p;
			p = stringn(b, p, display->black, ZP, font, buf, utfnlen(buf, tick));
			draw(b, Rect(p.x-1, p.y, p.x+2, p.y+3), display->black, nil, ZP);
			draw(b, Rect(p.x, p.y, p.x+1, p.y+h), display->black, nil, ZP);
			draw(b, Rect(p.x-1, p.y+h-3, p.x+2, p.y+h), display->black, nil, ZP);
			p = string(b, p, display->black, ZP, font, buf+tick);
		}
		flushimage(display, 1);

nodraw:
		i = Ekeyboard;
		if(m != nil)
			i |= Emouse;

		replclipr(b, 0, sc);
		i = eread(i, &ev);

		/* screen might have been resized */
		if(b != screen || !eqrect(screen->clipr, sc)){
			freeimage(save);
			save = nil;
		}
		b = screen;
		sc = b->clipr;
		replclipr(b, 0, b->r);

		switch(i){
		default:
			done = 1;
			n = -1;
			break;
		case Ekeyboard:
			k = ev.kbdc;
			if(buf == nil || k == Keof || k == '\n'){
				done = 1;
				break;
			}
			if(k == Knack || k == Kesc){
				done = !n;
				buf[n = tick = 0] = 0;
				break;
			}
			if(k == Ksoh || k == Khome){
				tick = 0;
				continue;
			}
			if(k == Kenq || k == Kend){
				tick = n;
				continue;
			}
			if(k == Kright){
				if(tick < n)
					tick += chartorune(&k, buf+tick);
				continue;
			}
			if(k == Kleft){
				for(i = 0; i < n; i += l){
					l = chartorune(&k, buf+tick);
					if(i+l >= tick){
						tick = i;
						break;
					}
				}
				continue;
			}
			if(k == Ketb){
				while(tick > 0){
					tick--;
					if(tick == 0 ||
					   strchr(" !\"#$%&'()*+,-./:;<=>?@`[\\]^{|}~", buf[tick-1]))
						break;
				}
				buf[n = tick] = 0;
				break;
			}
			if(k == Kbs){
				if(tick <= 0)
					continue;
				for(i = 0; i < n; i += l){
					l = chartorune(&k, buf+i);
					if(i+l >= tick){
						memmove(buf+i, buf+i+l, n - (i+l));
						buf[n -= l] = 0;
						tick -= l;
						break;
					}
				}
				break;
			}
			if(k < 0x20 || k == Kdel || (k & 0xFF00) == KF || (k & 0xFF00) == Spec)
				continue;
			if((len-n) <= (l = runelen(k)))
				continue;
			memmove(buf+tick+l, buf+tick, n - tick);
			runetochar(buf+tick, &k);
			buf[n += l] = 0;
			tick += l;
			break;
		case Emouse:
			*m = ev.mouse;
			if(!ptinrect(m->xy, r)){
				down = 0;
				goto nodraw;
			}
			if(m->buttons & 7){
				down = 1;
				if(buf && m->xy.x >= (t.x - w)){
					down = 0;
					for(i = 0; i < n; i += l){
						l = chartorune(&k, buf+i);
						t.x += stringnwidth(font, buf+i, 1);
						if(t.x > m->xy.x)
							break;
					}
					tick = i;
				}
				continue;
			}
			done = down;
			break;
		}
		if(save){
			draw(b, save->r, save, nil, save->r.min);
			freeimage(save);
			save = nil;
		}
	}

	replclipr(b, 0, sc);

	freeimage(backcol);
	freeimage(bordcol);
	flushimage(display, 1);

	return n;
}
Example #8
0
File: canvs.c Project: 8l/inferno
char*
tkdrawcanv(Tk *tk, Point orig)
{
	Image *dst;
	TkCitem *i;
	Display *d;
	TkCanvas *c;
	Rectangle r, bufr, oclipr;
	int vis, alpha, buffer;
	Point rel, p;
	TkCimeth *imeth;

	c = TKobj(TkCanvas, tk);
	d = tk->env->top->display;
	dst = tkimageof(tk);
	/*
	 * translation from local to screen coords
	 */
	rel.x = orig.x + tk->act.x + tk->borderwidth;
	rel.y = orig.y + tk->act.y + tk->borderwidth;

	buffer = c->buffer;
	if (buffer == TkCbufauto)
		buffer = TkCbufvisible;
/*		buffer = (dst == TKobj(TkWin, tk->env->top->root)->image) ? TkCbufvisible : TkCbufnone; */

	if (buffer == TkCbufnone) {
		if(c->image != nil && c->ialloc)
			freeimage(c->image);
		c->image = dst;
		c->ialloc = 0;

		r = tkrect(tk, 0);
		bufr = r;
		rectclip(&bufr, tk->dirty);
		oclipr = dst->clipr;

		replclipr(dst, 0, rectaddpt(bufr, rel));
		draw(dst, rectaddpt(bufr, rel), tkgc(tk->env, TkCbackgnd), nil, ZP);

		p = subpt(rel, c->view);
		p.x = TKI2F(p.x);
		p.y = TKI2F(p.y);
		bufr = rectaddpt(bufr, c->view);
		for(i = c->head; i; i = i->next) {
			if(rectXrect(i->p.bb, bufr)) {
				imeth = &tkcimethod[i->type];
				imeth->coord(i, nil, p.x, p.y);
				imeth->draw(dst, i, tk->env);
				imeth->coord(i, nil, -p.x, -p.y);
			}
		}
		replclipr(dst, 0, oclipr);
	} else {
		if (c->buffer == TkCbufall)
			bufr = c->region;
		else {
			bufr.min = c->view;
			bufr.max.x = c->view.x + tk->act.width;
			bufr.max.y = c->view.y + tk->act.height;
		}
		alpha = (tk->env->colors[TkCbackgnd] & 0xff) != 0xff;
		if(c->image == nil || eqrect(bufr, c->image->r) == 0) {
			if(c->image != nil && c->ialloc)
				freeimage(c->image);
			c->image = allocimage(d, bufr, alpha?RGBA32:d->image->chan, 0, tk->env->colors[TkCbackgnd]);
			c->ialloc = 1;
			c->update = bufr;
			tkcvssetdirty(tk);		/* unnecessary? */
		}
	
		if(c->image == nil)
			return nil;
	
		r = c->update;
		if (rectclip(&r, c->image->r)) {
			if (alpha)
				drawop(c->image, c->update, nil, nil, ZP, Clear);
			draw(c->image, c->update, tkgc(tk->env, TkCbackgnd), nil, c->view);
			replclipr(c->image, 0, r);
			for(i = c->head; i; i = i->next) {
				if(rectXrect(i->p.bb, r))
					tkcimethod[i->type].draw(c->image, i, tk->env);
			}
			replclipr(c->image, 0, c->image->r);
		}
		/*
		 * if the visible area of the canvas image doesn't
		 * fit completely within the dirty rectangle,
		 * then we'll need to draw the background behind it
		 */
		r = tkrect(tk, 0);
		bufr = rectsubpt(bufr, c->view);
		vis = rectclip(&bufr, tkrect(tk, 0));
	
		if (!vis || !rectinrect(tk->dirty, bufr))
			draw(dst, rectaddpt(tk->dirty, rel), tkgc(tk->env, TkCbackgnd), nil, c->view);
	
		if (vis && rectclip(&bufr, tk->dirty))
			draw(dst, rectaddpt(bufr, rel), c->image, nil, addpt(bufr.min, c->view));
	}


	/*
	 * if the border is dirty too, then draw that
	 */
	if (!rectinrect(tk->dirty, bufr)) {
		r.min = addpt(r.min, rel);
		r.min.x -= tk->borderwidth;
		r.min.y -= tk->borderwidth;
		tkdrawrelief(dst, tk, r.min, TkCbackgnd, tk->relief);
	}
	c->update = bbnil;
	return nil;
}
Example #9
0
void
coldragwin(Column *c, Window *w, int but)
{
	Rectangle r;
	int i, b;
	Point p, op;
	Window *v;
	Column *nc;

	clearmouse();
	setcursor(mousectl, &boxcursor);
	b = mouse->buttons;
	op = mouse->xy;
	while(mouse->buttons == b)
		readmouse(mousectl);
	setcursor(mousectl, nil);
	if(mouse->buttons){
		while(mouse->buttons)
			readmouse(mousectl);
		return;
	}

	for(i=0; i<c->nw; i++)
		if(c->w[i] == w)
			goto Found;
	error("can't find window");

  Found:
	p = mouse->xy;
	if(abs(p.x-op.x)<5 && abs(p.y-op.y)<5){
		colgrow(c, w, but);
		winmousebut(w);
		return;
	}
	/* is it a flick to the right? */
	if(abs(p.y-op.y)<10 && p.x>op.x+30 && rowwhichcol(c->row, p)==c)
		p.x = op.x+Dx(w->r);	/* yes: toss to next column */
	nc = rowwhichcol(c->row, p);
	if(nc!=nil && nc!=c){
		colclose(c, w, FALSE);
		coladd(nc, w, nil, p.y);
		winmousebut(w);
		return;
	}
	if(i==0 && c->nw==1)
		return;			/* can't do it */
	if((i>0 && p.y<c->w[i-1]->r.min.y) || (i<c->nw-1 && p.y>w->r.max.y)
	|| (i==0 && p.y>w->r.max.y)){
		/* shuffle */
		colclose(c, w, FALSE);
		coladd(c, w, nil, p.y);
		winmousebut(w);
		return;
	}
	if(i == 0)
		return;
	v = c->w[i-1];
	if(p.y < v->tag.all.max.y)
		p.y = v->tag.all.max.y;
	if(p.y > w->r.max.y-Dy(w->tag.all)-Border)
		p.y = w->r.max.y-Dy(w->tag.all)-Border;
	r = v->r;
	r.max.y = p.y;
	if(r.max.y > v->body.r.min.y){
		r.max.y -= (r.max.y-v->body.r.min.y)%v->body.font->height;
		if(v->body.r.min.y == v->body.r.max.y)
			r.max.y++;
	}
	if(!eqrect(v->r, r)){
		draw(screen, r, textcols[BACK], nil, ZP);
		winresize(v, r, c->safe);
	}
	r.min.y = v->r.max.y;
	r.max.y = r.min.y+Border;
	draw(screen, r, display->black, nil, ZP);
	r.min.y = r.max.y;
	if(i == c->nw-1)
		r.max.y = c->r.max.y;
	else
		r.max.y = c->w[i+1]->r.min.y-Border;
	if(!eqrect(w->r, r)){
		draw(screen, r, textcols[BACK], nil, ZP);
		winresize(w, r, c->safe);
	}
	c->safe = TRUE;
    	winmousebut(w);
}
Example #10
0
void
colgrow(Column *c, Window *w, int but)
{
	Rectangle r, cr;
	int i, j, k, l, y1, y2, *nl, *ny, tot, nnl, onl, dnl, h;
	Window *v;

	for(i=0; i<c->nw; i++)
		if(c->w[i] == w)
			goto Found;
	error("can't find window");

  Found:
	cr = c->r;
	if(but < 0){	/* make sure window fills its own space properly */
		r = w->r;
		if(i==c->nw-1 || c->safe==FALSE)
			r.max.y = cr.max.y;
		else
			r.max.y = c->w[i+1]->r.min.y;
		winresize(w, r, FALSE);
		return;
	}
	cr.min.y = c->w[0]->r.min.y;
	if(but == 3){	/* full size */
		if(i != 0){
			v = c->w[0];
			c->w[0] = w;
			c->w[i] = v;
		}
		draw(screen, cr, textcols[BACK], nil, ZP);
		winresize(w, cr, FALSE);
		for(i=1; i<c->nw; i++)
			c->w[i]->body.maxlines = 0;
		c->safe = FALSE;
		return;
	}
	/* store old #lines for each window */
	onl = w->body.maxlines;
	nl = emalloc(c->nw * sizeof(int));
	ny = emalloc(c->nw * sizeof(int));
	tot = 0;
	for(j=0; j<c->nw; j++){
		l = c->w[j]->body.maxlines;
		nl[j] = l;
		tot += l;
	}
	/* approximate new #lines for this window */
	if(but == 2){	/* as big as can be */
		memset(nl, 0, c->nw * sizeof(int));
		goto Pack;
	}
	nnl = min(onl + max(min(5, w->maxlines), onl/2), tot);
	if(nnl < w->maxlines)
		nnl = (w->maxlines+nnl)/2;
	if(nnl == 0)
		nnl = 2;
	dnl = nnl - onl;
	/* compute new #lines for each window */
	for(k=1; k<c->nw; k++){
		/* prune from later window */
		j = i+k;
		if(j<c->nw && nl[j]){
			l = min(dnl, max(1, nl[j]/2));
			nl[j] -= l;
			nl[i] += l;
			dnl -= l;
		}
		/* prune from earlier window */
		j = i-k;
		if(j>=0 && nl[j]){
			l = min(dnl, max(1, nl[j]/2));
			nl[j] -= l;
			nl[i] += l;
			dnl -= l;
		}
	}
    Pack:
	/* pack everyone above */
	y1 = cr.min.y;
	for(j=0; j<i; j++){
		v = c->w[j];
		r = v->r;
		r.min.y = y1;
		r.max.y = y1+Dy(v->tag.all);
		if(nl[j])
			r.max.y += 1 + nl[j]*v->body.font->height;
		if(!c->safe || !eqrect(v->r, r)){
			draw(screen, r, textcols[BACK], nil, ZP);
			winresize(v, r, c->safe);
		}
		r.min.y = v->r.max.y;
		r.max.y += Border;
		draw(screen, r, display->black, nil, ZP);
		y1 = r.max.y;
	}
	/* scan to see new size of everyone below */
	y2 = c->r.max.y;
	for(j=c->nw-1; j>i; j--){
		v = c->w[j];
		r = v->r;
		r.min.y = y2-Dy(v->tag.all);
		if(nl[j])
			r.min.y -= 1 + nl[j]*v->body.font->height;
		r.min.y -= Border;
		ny[j] = r.min.y;
		y2 = r.min.y;
	}
	/* compute new size of window */
	r = w->r;
	r.min.y = y1;
	r.max.y = r.min.y+Dy(w->tag.all);
	h = w->body.font->height;
	if(y2-r.max.y >= 1+h+Border){
		r.max.y += 1;
		r.max.y += h*((y2-r.max.y)/h);
	}
	/* draw window */
	if(!c->safe || !eqrect(w->r, r)){
		draw(screen, r, textcols[BACK], nil, ZP);
		winresize(w, r, c->safe);
	}
	if(i < c->nw-1){
		r.min.y = r.max.y;
		r.max.y += Border;
		draw(screen, r, display->black, nil, ZP);
		for(j=i+1; j<c->nw; j++)
			ny[j] -= (y2-r.max.y);
	}
	/* pack everyone below */
	y1 = r.max.y;
	for(j=i+1; j<c->nw; j++){
		v = c->w[j];
		r = v->r;
		r.min.y = y1;
		r.max.y = y1+Dy(v->tag.all);
		if(nl[j])
			r.max.y += 1 + nl[j]*v->body.font->height;
		if(!c->safe || !eqrect(v->r, r)){
			draw(screen, r, textcols[BACK], nil, ZP);
			winresize(v, r, c->safe);
		}
		if(j < c->nw-1){	/* no border on last window */
			r.min.y = v->r.max.y;
			r.max.y += Border;
			draw(screen, r, display->black, nil, ZP);
		}
		y1 = r.max.y;
	}
	r = w->r;
	r.min.y = y1;
	r.max.y = c->r.max.y;
	draw(screen, r, textcols[BACK], nil, ZP);
	free(nl);
	free(ny);
	c->safe = TRUE;
	winmousebut(w);
}
Example #11
0
static void
vgactl(char* a)
{
	int align, i, n, size, x, y, z;
	char *chanstr, *field[6], *p;
	ulong chan;
	VGAscr *scr;
	extern VGAdev *vgadev[];
	extern VGAcur *vgacur[];
	Rectangle r;

	n = tokenize(a, field, nelem(field));
	if(n < 1)
		error(Ebadarg);

	scr = &vgascreen[0];
	if(strcmp(field[0], "hwgc") == 0){
		if(n < 2)
			error(Ebadarg);

		if(strcmp(field[1], "off") == 0){
			lock(&cursor);
			if(scr->cur){
				if(scr->cur->disable)
					scr->cur->disable(scr);
				scr->cur = nil;
			}
			unlock(&cursor);
			return;
		}

		for(i = 0; vgacur[i]; i++){
			if(strcmp(field[1], vgacur[i]->name))
				continue;
			lock(&cursor);
			if(scr->cur && scr->cur->disable)
				scr->cur->disable(scr);
			scr->cur = vgacur[i];
			if(scr->cur->enable)
				scr->cur->enable(scr);
			unlock(&cursor);
			return;
		}
	}
	else if(strcmp(field[0], "type") == 0){
		if(n < 2)
			error(Ebadarg);

		for(i = 0; vgadev[i]; i++){
			if(strcmp(field[1], vgadev[i]->name))
				continue;
			if(scr->dev && scr->dev->disable)
				scr->dev->disable(scr);
			scr->dev = vgadev[i];
			if(scr->dev->enable)
				scr->dev->enable(scr);
			return;
		}
	}
	else if(strcmp(field[0], "size") == 0){
		if(n < 3)
			error(Ebadarg);
		if(drawhasclients())
			error(Ebusy);

		x = strtoul(field[1], &p, 0);
		if(x == 0 || x > 2048)
			error(Ebadarg);
		if(*p)
			p++;

		y = strtoul(p, &p, 0);
		if(y == 0 || y > 2048)
			error(Ebadarg);
		if(*p)
			p++;

		z = strtoul(p, &p, 0);

		chanstr = field[2];
		if((chan = strtochan(chanstr)) == 0)
			error("bad channel");

		if(chantodepth(chan) != z)
			error("depth, channel do not match");

		cursoroff(1);
		deletescreenimage();
		if(screensize(x, y, z, chan))
			error(Egreg);
		vgascreenwin(scr);
		cursoron(1);
		return;
	}
	else if(strcmp(field[0], "actualsize") == 0){
		if(scr->gscreen == nil)
			error("set the screen size first");

		if(n < 2)
			error(Ebadarg);
		x = strtoul(field[1], &p, 0);
		if(x == 0 || x > 2048)
			error(Ebadarg);
		if(*p)
			p++;

		y = strtoul(p, nil, 0);
		if(y == 0 || y > 2048)
			error(Ebadarg);

		if(x > scr->gscreen->r.max.x || y > scr->gscreen->r.max.y)
			error("physical screen bigger than virtual");

		r = Rect(0,0,x,y);
		if(!eqrect(r, scr->gscreen->r)){
			if(scr->cur == nil || scr->cur->doespanning == 0)
				error("virtual screen not supported");
		}

		physgscreenr = r;
		return;
	}
	else if(strcmp(field[0], "palettedepth") == 0){
		if(n < 2)
			error(Ebadarg);

		x = strtoul(field[1], &p, 0);
		if(x != 8 && x != 6)
			error(Ebadarg);

		scr->palettedepth = x;
		return;
	}
	else if(strcmp(field[0], "drawinit") == 0){
		if(scr && scr->dev && scr->dev->drawinit)
			scr->dev->drawinit(scr);
		return;
	}
	else if(strcmp(field[0], "linear") == 0){
		if(n < 2)
			error(Ebadarg);

		size = strtoul(field[1], 0, 0);
		if(n < 3)
			align = 0;
		else
			align = strtoul(field[2], 0, 0);
		if(screenaperture(size, align))
			error("not enough free address space");
		return;
	}
/*	else if(strcmp(field[0], "memset") == 0){
		if(n < 4)
			error(Ebadarg);
		memset((void*)strtoul(field[1], 0, 0), atoi(field[2]), atoi(field[3]));
		return;
	}
*/
	else if(strcmp(field[0], "blank") == 0){
		if(n < 1)
			error(Ebadarg);
		drawblankscreen(1);
		return;
	}
	else if(strcmp(field[0], "blanktime") == 0){
		if(n < 2)
			error(Ebadarg);
		blanktime = strtoul(field[1], 0, 0);
		return;
	}
	else if(strcmp(field[0], "hwaccel") == 0){
		if(n < 2)
			error(Ebadarg);
		if(strcmp(field[1], "on") == 0)
			hwaccel = 1;
		else if(strcmp(field[1], "off") == 0)
			hwaccel = 0;
		return;
	}
	else if(strcmp(field[0], "hwblank") == 0){
		if(n < 2)
			error(Ebadarg);
		if(strcmp(field[1], "on") == 0)
			hwblank = 1;
		else if(strcmp(field[1], "off") == 0)
			hwblank = 0;
		return;
	}

	error(Ebadarg);
}