Charles.Forsyth20060303a828770d19 years agoHistory
1295 lines · 23.4 KB · C
RawDownload
#include "lib9.h"#include "interp.h"#include "isa.h"#include "runt.h"#include "draw.h"#include "tk.h"#include "tkmod.h"#include "pool.h"#include "drawif.h"#include "keyboard.h"#include "raise.h"#include "kernel.h" extern	void	tkfreetop(Heap*, int);Type*	fakeTkTop;static	uchar	TktypeMap[] = Tk_Toplevel_map;int	tkstylus;void	(*tkwiretap)(void*, char*, char*, void*, Rectangle*); static void tktopimagedptr(TkTop*, Draw_Image*);static char*tkputwinimage(Tk*, Draw_Image*, int); static voidlockctxt(TkCtxt *ctxt){	libqlock(ctxt->lock);} static voidunlockctxt(TkCtxt *ctxt){	libqunlock(ctxt->lock);} static voidtkmarktop(Type *t, void *vw){	Heap *h;	TkVar *v;	TkPanelimage *di;	TkTop *top;	Tk *w, *next;	TkWin *tkw; 	markheap(t, vw);	top = vw;	// XXX do we need to lock context here??	for(v = top->vars; v; v = v->link) {		if(v->type == TkVchan) {			h = D2H(v->value);			Setmark(h);		}	}	for (di = top->panelimages; di != nil; di = di->link) {		h = D2H(di->image);		Setmark(h);	}	for(w = top->windows; w != nil; w = next){		tkw = TKobj(TkWin, w);		if(tkw->image != nil){			h = D2H(tkw->di);			Setmark(h);		}		next = tkw->next;	}} voidtkmodinit(void){	builtinmod("$Tk", Tkmodtab, Tkmodlen);	fmtinstall('v', tkeventfmt);			/* XXX */ 	fakeTkTop = dtype(tkfreetop, sizeof(TkTop), TktypeMap, sizeof(TktypeMap));	fakeTkTop->mark = tkmarktop; 	tksorttable();} voidTk_toplevel(void *a){	Tk *tk;	Heap *h;	TkTop *t;	TkWin *tkw;	TkCtxt *ctxt;	Display *disp;	F_Tk_toplevel *f = a;	void *r; 	r = *f->ret;	*f->ret = H;	destroy(r);	disp = checkdisplay(f->d); 	h = heapz(fakeTkTop);	t = H2D(TkTop*, h);	poolimmutable(h); 	t->dd = f->d;	D2H(t->dd)->ref++; 	t->execdepth = -1;	t->display = disp; 	tk = tknewobj(t, TKframe, sizeof(Tk)+sizeof(TkWin));	if(tk == nil) {		destroy(t);		return;	} 	tk->act.x = 0;	tk->act.y = 0;	tk->act.width = 1;		/* XXX why not zero? */	tk->act.height = 1;	tk->flag |= Tkwindow; 	tkw = TKobj(TkWin, tk);	tkw->di = H; 	tktopopt(tk, string2c(f->arg));		tk->geom = tkmoveresize;	tk->name = tkmkname(".");	if(tk->name == nil) {		tkfreeobj(tk);		destroy(t);		return;	} 	ctxt = tknewctxt(disp);	if(ctxt == nil) {		tkfreeobj(tk);		destroy(t);		return;	}	t->ctxt = ctxt;	t->screenr = disp->image->r; 	tkw->next = t->windows;	t->windows = tk;	t->root = tk;	Setmark(h);	poolmutable(h);	t->wreq = cnewc(&Tptr, movp, 8);	*f->ret = (Tk_Toplevel*)t;} voidTk_cmd(void *a){	TkTop *t;	char *val, *e;	F_Tk_cmd *f = a; 	t = (TkTop*)f->t;	if(t == H || D2H(t)->t != fakeTkTop) {		retstr(TkNotop, f->ret);		return;	}	lockctxt(t->ctxt);	val = nil;	e = tkexec(t, string2c(f->arg), &val);	unlockctxt(t->ctxt);	if(e == TkNomem){		free(val);		error(exNomem);		/* what about f->ret? */	}	if(e != nil && t->errx[0] != '\0'){		char *s = tkerrstr(t, e); 		retstr(s, f->ret);		free(s);	}	else		retstr(e == nil ? val : e, f->ret);	if(tkwiretap != nil)		tkwiretap(t, string2c(f->arg), val, nil, nil);	free(val);} voidTk_color(void *fp){	ulong rgba;	F_Tk_color *f = fp;	if(tkparsecolor(string2c(f->col), &rgba) != nil)		*f->ret = DNotacolor;	else		*f->ret = rgba;} voidTk_rect(void *fp){	F_Tk_rect *f = fp;	Tk *tk;	TkTop *t;	Rectangle r;	TkGeom *g;	Point o;	int bd, flags; 	t = (TkTop*)f->t;	if(t == H || D2H(t)->t != fakeTkTop){		*(Rectangle *)f->ret = ZR;		return;	}	lockctxt(t->ctxt);	tk = tklook(t, string2c(f->name), 0);	if(tk == nil){		*(Rectangle *)f->ret = ZR;		unlockctxt(t->ctxt);		return;	}	o = tkposn(tk);	flags = f->flags;	if(flags & Tk_Local)		o = subpt(o, tkposn(tk->env->top->root));	bd = tk->borderwidth;	g = (flags & Tk_Required) ? &tk->req : &tk->act;	if(flags & Tk_Border){		r.min = o;		r.max.x = r.min.x + g->width + bd + bd;		r.max.y = r.min.y + g->height + bd + bd;	} else {		r.min.x = o.x + bd;		r.min.y = o.y + bd;		r.max.x = r.min.x + g->width;		r.max.y = r.min.y + g->height;	}	*(Rectangle *)f->ret = r;	unlockctxt(t->ctxt);} inttkdescendant(Tk *p, Tk *c){	int n; 	if(c == nil || p->env->top != c->env->top)		return 0; 	if (p->name != nil && c->name != nil) { 		n = strlen(p->name->name);		if(strncmp(p->name->name, c->name->name, n) == 0)			return 1;	} 	return 0;} voidtkenterleave(TkTop *t){	Tk *fw, *ent;	TkMouse m;	TkTop *t1, *t2;	TkCtxt *c; 	c = t->ctxt;	m = c->mstate; 	if (c->mgrab != nil && (c->mgrab->flag & Tknograb)) {		fw = tkfindfocus(t, m.x, m.y, 1);		if (fw != c->mgrab && fw != nil && (fw->flag & Tknograb) == 0)			fw = nil;	} else if (c->focused) {		fw = tkfindfocus(t, m.x, m.y, 1);		if (fw != c->mfocus)			fw = nil;	} else if (c->mgrab != nil) {		fw = tkfindfocus(t, m.x, m.y, 1);		if (fw != nil) {			if (!tkdescendant(c->mgrab, fw) && !(fw->flag & c->mgrab->flag & Tknograb))				fw = nil;		}	} else if (m.b == 0)		fw = tkfindfocus(t, m.x, m.y, 0);	else if (tkfindfocus(t, m.x, m.y, 1) == c->entered)		return;	else		fw = nil;  	if (c->entered == fw)		return; 	t1 = t2 = nil;	if (c->entered != nil) {		ent = c->entered;		t1 = ent->env->top;		c->entered = nil;		tkdeliver(ent, TkLeave, nil);	} 	if (fw != nil) {		t2 = fw->env->top;		c->entered = fw;		tkdeliver(fw, TkEnter, &m);	}	if (t1 != nil)		tkupdate(t1);	if (t2 != nil && t1 != t2)		tkupdate(t2);} voidTk_pointer(void *a){	static int buttonr[] = {TkButton1R, TkButton2R, TkButton3R, TkButton4R, TkButton5R, TkButton6R};	static int buttonp[] = {TkButton1P, TkButton2P, TkButton3P, TkButton4P, TkButton5P, TkButton6P};	Tk *fw, *target, *dest, *ent;	TkMouse m;	TkCtxt *c;	TkTop *t, *ot;	int d, dtype, etype;	F_Tk_pointer *f = a;	int b, lastb, inside; 	t = (TkTop*)f->t;	if(t == H || D2H(t)->t != fakeTkTop)		return; 	c = t->ctxt; 	/* ignore no-button-motion for emulated stylus input */	if(tkstylus && c->mstate.b == 0 && (f->p.buttons&0x1f)==0)		return; 	lockctxt(c);//if (f->p.buttons != 0 || c->mstate.b != 0)//print("tkmouse %d [%d %d], focused %d[%s], grab %s, entered %s\n",//	f->p.buttons, f->p.xy.x, f->p.xy.y, c->focused, tkname(c->mfocus), tkname(c->mgrab), tkname(c->entered));	/*	 * target is the widget that we're deliver the mouse event to.	 * inside is true if the mouse point is located inside target.	 */	inside = 1;	if (c->mgrab != nil && (c->mgrab->flag & Tknograb)) {		fw = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 1);		if (fw != nil && (fw->flag & Tknograb))			target = fw;		else {			target = c->mgrab;			inside = 0;		}	} else if (c->focused) {		if (c->mfocus != nil) {			fw = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 1);			if (fw != c->mfocus)				inside = 0;		}		target = c->mfocus;	} else if (c->mgrab != nil && (c->mgrab->flag & Tkdisabled) == 0) {		/*		 * XXX this isn't quite right, as perhaps we should do a tkinwindow()		 * (below the grab).		 * so that events to containers underneath the grab arrive		 * via the containers (as is usual)		 */		fw = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 1);		if (fw != nil && tkdescendant(c->mgrab, fw))			target = fw;		else {			target = c->mgrab;			inside = 0;		}	} else		target = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 0); 	lastb = c->mstate.b;	c->mstate.x = f->p.xy.x;	c->mstate.y = f->p.xy.y;	c->mstate.b = f->p.buttons & 0x1f;		/* Just the buttons */	m = c->mstate; 	/* XXX if the mouse is being moved with the buttons held down	 * and we've no mfocus and no mgrab then ignore	 * the event as our original target has gone away (or never existed)	 */	if (lastb && m.b && !c->focused && c->mgrab == nil)		target = nil; 	if (target != c->entered || (c->entered != nil && !inside)) {		if (c->entered != nil) {			fw = c->entered;			c->entered =  nil;			tkdeliver(fw, TkLeave, nil);			if (target == nil || fw->env->top != target->env->top)				tkupdate(fw->env->top);		}		if (inside) {			c->entered = target;			tkdeliver(target, TkEnter, &m);		}	} 	dest = nil;	if (target != nil) {		etype = 0;		dtype = 0;		if(f->p.buttons & (1<<8))		/* Double */			dtype = TkDouble;			d = lastb ^ m.b;		if (d)	{			/* cancel any autorepeat, notifying existing client */			tkrepeat(nil, nil, nil, 0, 0);			if (d & ~lastb & 1)		/* button 1 potentially takes the focus */				tkdeliver(target, TkTakefocus|TkButton1P, &m);		}		for(b=0; b<nelem(buttonp); b++){			if(d & (1<<b)){				etype = buttonr[b];				if(m.b & (1<<b))					etype = buttonp[b]|dtype;				dest = tkdeliver(target, etype, &m);			}		}		if(tkstylus && m.b==0) {			if ((ent = c->entered) != nil) {				c->entered = nil;				ot = ent->env->top;				tkdeliver(ent, TkLeave, nil);				if (ot != target->env->top)					tkupdate(ot);			}		} else if(etype == 0) {			etype = TkMotion;			for(b = 0; b<nelem(buttonp); b++)				if (m.b & (1<<b))					etype |= buttonp[b];			tkdeliver(target, etype, &m);		}		if (m.b != 0) {			if (lastb == 0 && !c->focused) {		/* (some deliver might have grabbed it...) */				if (dest == nil)					dest = target;				if ((dest->flag & Tknograb) == 0) {					c->focused = 1;					c->mfocus = dest;				}			}		} else {			c->focused = 0;			c->mfocus = nil;			if (lastb != 0)				tkenterleave(t);		}		tkupdate(target->env->top);	} else if (c->focused && m.b == 0) {		c->focused = 0;		tkenterleave(t);	}	unlockctxt(c);} voidTk_keyboard(void *a){	Tk *grab;	TkTop *t;	TkCtxt *c;	F_Tk_keyboard *f = a; 	t = (TkTop*)f->t;	if(t == H || D2H(t)->t != fakeTkTop)		return;	c = t->ctxt;	if (c == nil)		return;	lockctxt(c);	if (c->tkmenu != nil)		grab = c->tkmenu;	else		grab = c->tkkeygrab;	if(grab == nil){		unlockctxt(c);		return;	} 	t = grab->env->top;	tkdeliver(grab, TkKey|TKKEY(f->key), nil);	tkupdate(t);	unlockctxt(c);} TkVar*tkmkvar(TkTop *t, char *name, int type){	TkVar *v; 	for(v = t->vars; v; v = v->link)		if(strcmp(v->name, name) == 0)			return v; 	if(type == 0)		return nil; 

Lines 1–500 of 1295.