137da2899SCharles.Forsyth #include "lib9.h"
237da2899SCharles.Forsyth #include "interp.h"
337da2899SCharles.Forsyth #include "isa.h"
437da2899SCharles.Forsyth #include "runt.h"
537da2899SCharles.Forsyth #include "draw.h"
637da2899SCharles.Forsyth #include "tk.h"
737da2899SCharles.Forsyth #include "tkmod.h"
837da2899SCharles.Forsyth #include "pool.h"
937da2899SCharles.Forsyth #include "drawif.h"
1037da2899SCharles.Forsyth #include "keyboard.h"
1137da2899SCharles.Forsyth #include "raise.h"
1237da2899SCharles.Forsyth #include "kernel.h"
1337da2899SCharles.Forsyth
1437da2899SCharles.Forsyth extern void tkfreetop(Heap*, int);
1537da2899SCharles.Forsyth Type* fakeTkTop;
1637da2899SCharles.Forsyth static uchar TktypeMap[] = Tk_Toplevel_map;
1737da2899SCharles.Forsyth int tkstylus;
1837da2899SCharles.Forsyth void (*tkwiretap)(void*, char*, char*, void*, Rectangle*);
1937da2899SCharles.Forsyth
2037da2899SCharles.Forsyth static void tktopimagedptr(TkTop*, Draw_Image*);
2137da2899SCharles.Forsyth static char*tkputwinimage(Tk*, Draw_Image*, int);
2237da2899SCharles.Forsyth
2337da2899SCharles.Forsyth static void
lockctxt(TkCtxt * ctxt)2437da2899SCharles.Forsyth lockctxt(TkCtxt *ctxt)
2537da2899SCharles.Forsyth {
2637da2899SCharles.Forsyth libqlock(ctxt->lock);
2737da2899SCharles.Forsyth }
2837da2899SCharles.Forsyth
2937da2899SCharles.Forsyth static void
unlockctxt(TkCtxt * ctxt)3037da2899SCharles.Forsyth unlockctxt(TkCtxt *ctxt)
3137da2899SCharles.Forsyth {
3237da2899SCharles.Forsyth libqunlock(ctxt->lock);
3337da2899SCharles.Forsyth }
3437da2899SCharles.Forsyth
3537da2899SCharles.Forsyth static void
tkmarktop(Type * t,void * vw)3637da2899SCharles.Forsyth tkmarktop(Type *t, void *vw)
3737da2899SCharles.Forsyth {
3837da2899SCharles.Forsyth Heap *h;
3937da2899SCharles.Forsyth TkVar *v;
4037da2899SCharles.Forsyth TkPanelimage *di;
4137da2899SCharles.Forsyth TkTop *top;
4237da2899SCharles.Forsyth Tk *w, *next;
4337da2899SCharles.Forsyth TkWin *tkw;
4437da2899SCharles.Forsyth
4537da2899SCharles.Forsyth markheap(t, vw);
4637da2899SCharles.Forsyth top = vw;
4737da2899SCharles.Forsyth // XXX do we need to lock context here??
4837da2899SCharles.Forsyth for(v = top->vars; v; v = v->link) {
4937da2899SCharles.Forsyth if(v->type == TkVchan) {
5037da2899SCharles.Forsyth h = D2H(v->value);
5137da2899SCharles.Forsyth Setmark(h);
5237da2899SCharles.Forsyth }
5337da2899SCharles.Forsyth }
5437da2899SCharles.Forsyth for (di = top->panelimages; di != nil; di = di->link) {
5537da2899SCharles.Forsyth h = D2H(di->image);
5637da2899SCharles.Forsyth Setmark(h);
5737da2899SCharles.Forsyth }
5837da2899SCharles.Forsyth for(w = top->windows; w != nil; w = next){
5937da2899SCharles.Forsyth tkw = TKobj(TkWin, w);
6037da2899SCharles.Forsyth if(tkw->image != nil){
6137da2899SCharles.Forsyth h = D2H(tkw->di);
6237da2899SCharles.Forsyth Setmark(h);
6337da2899SCharles.Forsyth }
6437da2899SCharles.Forsyth next = tkw->next;
6537da2899SCharles.Forsyth }
6637da2899SCharles.Forsyth }
6737da2899SCharles.Forsyth
6837da2899SCharles.Forsyth void
tkmodinit(void)6937da2899SCharles.Forsyth tkmodinit(void)
7037da2899SCharles.Forsyth {
7137da2899SCharles.Forsyth builtinmod("$Tk", Tkmodtab, Tkmodlen);
7237da2899SCharles.Forsyth fmtinstall('v', tkeventfmt); /* XXX */
7337da2899SCharles.Forsyth
7437da2899SCharles.Forsyth fakeTkTop = dtype(tkfreetop, sizeof(TkTop), TktypeMap, sizeof(TktypeMap));
7537da2899SCharles.Forsyth fakeTkTop->mark = tkmarktop;
7637da2899SCharles.Forsyth
7737da2899SCharles.Forsyth tksorttable();
7837da2899SCharles.Forsyth }
7937da2899SCharles.Forsyth
8037da2899SCharles.Forsyth void
Tk_toplevel(void * a)8137da2899SCharles.Forsyth Tk_toplevel(void *a)
8237da2899SCharles.Forsyth {
8337da2899SCharles.Forsyth Tk *tk;
8437da2899SCharles.Forsyth Heap *h;
8537da2899SCharles.Forsyth TkTop *t;
8637da2899SCharles.Forsyth TkWin *tkw;
8737da2899SCharles.Forsyth TkCtxt *ctxt;
8837da2899SCharles.Forsyth Display *disp;
8937da2899SCharles.Forsyth F_Tk_toplevel *f = a;
9037da2899SCharles.Forsyth void *r;
9137da2899SCharles.Forsyth
9237da2899SCharles.Forsyth r = *f->ret;
9337da2899SCharles.Forsyth *f->ret = H;
9437da2899SCharles.Forsyth destroy(r);
9537da2899SCharles.Forsyth disp = checkdisplay(f->d);
9637da2899SCharles.Forsyth
9737da2899SCharles.Forsyth h = heapz(fakeTkTop);
9837da2899SCharles.Forsyth t = H2D(TkTop*, h);
9937da2899SCharles.Forsyth poolimmutable(h);
10037da2899SCharles.Forsyth
10137da2899SCharles.Forsyth t->dd = f->d;
10237da2899SCharles.Forsyth D2H(t->dd)->ref++;
10337da2899SCharles.Forsyth
10437da2899SCharles.Forsyth t->execdepth = -1;
10537da2899SCharles.Forsyth t->display = disp;
10637da2899SCharles.Forsyth
10737da2899SCharles.Forsyth tk = tknewobj(t, TKframe, sizeof(Tk)+sizeof(TkWin));
10837da2899SCharles.Forsyth if(tk == nil) {
10937da2899SCharles.Forsyth destroy(t);
11037da2899SCharles.Forsyth return;
11137da2899SCharles.Forsyth }
11237da2899SCharles.Forsyth
11337da2899SCharles.Forsyth tk->act.x = 0;
11437da2899SCharles.Forsyth tk->act.y = 0;
11537da2899SCharles.Forsyth tk->act.width = 1; /* XXX why not zero? */
11637da2899SCharles.Forsyth tk->act.height = 1;
11737da2899SCharles.Forsyth tk->flag |= Tkwindow;
11837da2899SCharles.Forsyth
11937da2899SCharles.Forsyth tkw = TKobj(TkWin, tk);
12037da2899SCharles.Forsyth tkw->di = H;
12137da2899SCharles.Forsyth
12237da2899SCharles.Forsyth tktopopt(tk, string2c(f->arg));
12337da2899SCharles.Forsyth
12437da2899SCharles.Forsyth tk->geom = tkmoveresize;
12537da2899SCharles.Forsyth tk->name = tkmkname(".");
12637da2899SCharles.Forsyth if(tk->name == nil) {
12737da2899SCharles.Forsyth tkfreeobj(tk);
12837da2899SCharles.Forsyth destroy(t);
12937da2899SCharles.Forsyth return;
13037da2899SCharles.Forsyth }
13137da2899SCharles.Forsyth
13237da2899SCharles.Forsyth ctxt = tknewctxt(disp);
13337da2899SCharles.Forsyth if(ctxt == nil) {
13437da2899SCharles.Forsyth tkfreeobj(tk);
13537da2899SCharles.Forsyth destroy(t);
13637da2899SCharles.Forsyth return;
13737da2899SCharles.Forsyth }
13837da2899SCharles.Forsyth t->ctxt = ctxt;
13937da2899SCharles.Forsyth t->screenr = disp->image->r;
14037da2899SCharles.Forsyth
14137da2899SCharles.Forsyth tkw->next = t->windows;
14237da2899SCharles.Forsyth t->windows = tk;
14337da2899SCharles.Forsyth t->root = tk;
14437da2899SCharles.Forsyth Setmark(h);
14537da2899SCharles.Forsyth poolmutable(h);
14637da2899SCharles.Forsyth t->wreq = cnewc(&Tptr, movp, 8);
14737da2899SCharles.Forsyth *f->ret = (Tk_Toplevel*)t;
14837da2899SCharles.Forsyth }
14937da2899SCharles.Forsyth
15037da2899SCharles.Forsyth void
Tk_cmd(void * a)15137da2899SCharles.Forsyth Tk_cmd(void *a)
15237da2899SCharles.Forsyth {
15337da2899SCharles.Forsyth TkTop *t;
15437da2899SCharles.Forsyth char *val, *e;
15537da2899SCharles.Forsyth F_Tk_cmd *f = a;
15637da2899SCharles.Forsyth
15737da2899SCharles.Forsyth t = (TkTop*)f->t;
15837da2899SCharles.Forsyth if(t == H || D2H(t)->t != fakeTkTop) {
15937da2899SCharles.Forsyth retstr(TkNotop, f->ret);
16037da2899SCharles.Forsyth return;
16137da2899SCharles.Forsyth }
16237da2899SCharles.Forsyth lockctxt(t->ctxt);
16337da2899SCharles.Forsyth val = nil;
16437da2899SCharles.Forsyth e = tkexec(t, string2c(f->arg), &val);
16537da2899SCharles.Forsyth unlockctxt(t->ctxt);
16637da2899SCharles.Forsyth if(e == TkNomem){
16737da2899SCharles.Forsyth free(val);
16837da2899SCharles.Forsyth error(exNomem); /* what about f->ret? */
16937da2899SCharles.Forsyth }
17037da2899SCharles.Forsyth if(e != nil && t->errx[0] != '\0'){
17137da2899SCharles.Forsyth char *s = tkerrstr(t, e);
17237da2899SCharles.Forsyth
17337da2899SCharles.Forsyth retstr(s, f->ret);
17437da2899SCharles.Forsyth free(s);
17537da2899SCharles.Forsyth }
17637da2899SCharles.Forsyth else
17737da2899SCharles.Forsyth retstr(e == nil ? val : e, f->ret);
17837da2899SCharles.Forsyth if(tkwiretap != nil)
17937da2899SCharles.Forsyth tkwiretap(t, string2c(f->arg), val, nil, nil);
18037da2899SCharles.Forsyth free(val);
18137da2899SCharles.Forsyth }
18237da2899SCharles.Forsyth
18337da2899SCharles.Forsyth void
Tk_color(void * fp)18437da2899SCharles.Forsyth Tk_color(void *fp)
18537da2899SCharles.Forsyth {
18637da2899SCharles.Forsyth ulong rgba;
18737da2899SCharles.Forsyth F_Tk_color *f = fp;
18837da2899SCharles.Forsyth if(tkparsecolor(string2c(f->col), &rgba) != nil)
18937da2899SCharles.Forsyth *f->ret = DNotacolor;
19037da2899SCharles.Forsyth else
19137da2899SCharles.Forsyth *f->ret = rgba;
19237da2899SCharles.Forsyth }
19337da2899SCharles.Forsyth
19437da2899SCharles.Forsyth void
Tk_rect(void * fp)19537da2899SCharles.Forsyth Tk_rect(void *fp)
19637da2899SCharles.Forsyth {
19737da2899SCharles.Forsyth F_Tk_rect *f = fp;
19837da2899SCharles.Forsyth Tk *tk;
19937da2899SCharles.Forsyth TkTop *t;
20037da2899SCharles.Forsyth Rectangle r;
20137da2899SCharles.Forsyth Point o;
202*e298470bSforsyth int bd, flags, w, h;
20337da2899SCharles.Forsyth
20437da2899SCharles.Forsyth t = (TkTop*)f->t;
20537da2899SCharles.Forsyth if(t == H || D2H(t)->t != fakeTkTop){
20637da2899SCharles.Forsyth *(Rectangle*)f->ret = ZR;
20737da2899SCharles.Forsyth return;
20837da2899SCharles.Forsyth }
20937da2899SCharles.Forsyth lockctxt(t->ctxt);
21037da2899SCharles.Forsyth tk = tklook(t, string2c(f->name), 0);
21137da2899SCharles.Forsyth if(tk == nil){
21237da2899SCharles.Forsyth *(Rectangle*)f->ret = ZR;
21337da2899SCharles.Forsyth unlockctxt(t->ctxt);
21437da2899SCharles.Forsyth return;
21537da2899SCharles.Forsyth }
21637da2899SCharles.Forsyth o = tkposn(tk);
21737da2899SCharles.Forsyth flags = f->flags;
21837da2899SCharles.Forsyth if(flags & Tk_Local)
21937da2899SCharles.Forsyth o = subpt(o, tkposn(tk->env->top->root));
220*e298470bSforsyth if(flags & Tk_Required){
221*e298470bSforsyth h = tk->req.height;
222*e298470bSforsyth w = tk->req.width;
223*e298470bSforsyth }else{
224*e298470bSforsyth h = tk->act.height;
225*e298470bSforsyth w = tk->act.width;
226*e298470bSforsyth }
227*e298470bSforsyth unlockctxt(t->ctxt);
228*e298470bSforsyth if(w < 0)
229*e298470bSforsyth w = 0;
230*e298470bSforsyth if(h < 0)
231*e298470bSforsyth h = 0;
23237da2899SCharles.Forsyth bd = tk->borderwidth;
233*e298470bSforsyth if(bd < 0)
234*e298470bSforsyth bd = 0;
23537da2899SCharles.Forsyth if(flags & Tk_Border){
23637da2899SCharles.Forsyth r.min = o;
237*e298470bSforsyth r.max.x = r.min.x + w + bd + bd;
238*e298470bSforsyth r.max.y = r.min.y + h + bd + bd;
23937da2899SCharles.Forsyth }else{
24037da2899SCharles.Forsyth r.min.x = o.x + bd;
24137da2899SCharles.Forsyth r.min.y = o.y + bd;
242*e298470bSforsyth r.max.x = r.min.x + w;
243*e298470bSforsyth r.max.y = r.min.y + h;
24437da2899SCharles.Forsyth }
24537da2899SCharles.Forsyth *(Rectangle*)f->ret = r;
24637da2899SCharles.Forsyth }
24737da2899SCharles.Forsyth
24837da2899SCharles.Forsyth int
tkdescendant(Tk * p,Tk * c)24937da2899SCharles.Forsyth tkdescendant(Tk *p, Tk *c)
25037da2899SCharles.Forsyth {
25137da2899SCharles.Forsyth int n;
25237da2899SCharles.Forsyth
25337da2899SCharles.Forsyth if(c == nil || p->env->top != c->env->top)
25437da2899SCharles.Forsyth return 0;
25537da2899SCharles.Forsyth
25637da2899SCharles.Forsyth if (p->name != nil && c->name != nil) {
25737da2899SCharles.Forsyth n = strlen(p->name->name);
25837da2899SCharles.Forsyth if(strncmp(p->name->name, c->name->name, n) == 0)
25937da2899SCharles.Forsyth return 1;
26037da2899SCharles.Forsyth }
26137da2899SCharles.Forsyth
26237da2899SCharles.Forsyth return 0;
26337da2899SCharles.Forsyth }
26437da2899SCharles.Forsyth
26537da2899SCharles.Forsyth void
tkenterleave(TkTop * t)26637da2899SCharles.Forsyth tkenterleave(TkTop *t)
26737da2899SCharles.Forsyth {
26837da2899SCharles.Forsyth Tk *fw, *ent;
26937da2899SCharles.Forsyth TkMouse m;
27037da2899SCharles.Forsyth TkTop *t1, *t2;
27137da2899SCharles.Forsyth TkCtxt *c;
27237da2899SCharles.Forsyth
27337da2899SCharles.Forsyth c = t->ctxt;
27437da2899SCharles.Forsyth m = c->mstate;
27537da2899SCharles.Forsyth
27637da2899SCharles.Forsyth if (c->mgrab != nil && (c->mgrab->flag & Tknograb)) {
27737da2899SCharles.Forsyth fw = tkfindfocus(t, m.x, m.y, 1);
27837da2899SCharles.Forsyth if (fw != c->mgrab && fw != nil && (fw->flag & Tknograb) == 0)
27937da2899SCharles.Forsyth fw = nil;
28037da2899SCharles.Forsyth } else if (c->focused) {
28137da2899SCharles.Forsyth fw = tkfindfocus(t, m.x, m.y, 1);
28237da2899SCharles.Forsyth if (fw != c->mfocus)
28337da2899SCharles.Forsyth fw = nil;
28437da2899SCharles.Forsyth } else if (c->mgrab != nil) {
28537da2899SCharles.Forsyth fw = tkfindfocus(t, m.x, m.y, 1);
28637da2899SCharles.Forsyth if (fw != nil) {
28737da2899SCharles.Forsyth if (!tkdescendant(c->mgrab, fw) && !(fw->flag & c->mgrab->flag & Tknograb))
28837da2899SCharles.Forsyth fw = nil;
28937da2899SCharles.Forsyth }
29037da2899SCharles.Forsyth } else if (m.b == 0)
29137da2899SCharles.Forsyth fw = tkfindfocus(t, m.x, m.y, 0);
29237da2899SCharles.Forsyth else if (tkfindfocus(t, m.x, m.y, 1) == c->entered)
29337da2899SCharles.Forsyth return;
29437da2899SCharles.Forsyth else
29537da2899SCharles.Forsyth fw = nil;
29637da2899SCharles.Forsyth
29737da2899SCharles.Forsyth if (c->entered == fw)
29837da2899SCharles.Forsyth return;
29937da2899SCharles.Forsyth
30037da2899SCharles.Forsyth t1 = t2 = nil;
30137da2899SCharles.Forsyth if (c->entered != nil) {
30237da2899SCharles.Forsyth ent = c->entered;
30337da2899SCharles.Forsyth t1 = ent->env->top;
30437da2899SCharles.Forsyth c->entered = nil;
30537da2899SCharles.Forsyth tkdeliver(ent, TkLeave, nil);
30637da2899SCharles.Forsyth }
30737da2899SCharles.Forsyth
30837da2899SCharles.Forsyth if (fw != nil) {
30937da2899SCharles.Forsyth t2 = fw->env->top;
31037da2899SCharles.Forsyth c->entered = fw;
31137da2899SCharles.Forsyth tkdeliver(fw, TkEnter, &m);
31237da2899SCharles.Forsyth }
31337da2899SCharles.Forsyth if (t1 != nil)
31437da2899SCharles.Forsyth tkupdate(t1);
31537da2899SCharles.Forsyth if (t2 != nil && t1 != t2)
31637da2899SCharles.Forsyth tkupdate(t2);
31737da2899SCharles.Forsyth }
31837da2899SCharles.Forsyth
31937da2899SCharles.Forsyth void
Tk_pointer(void * a)32037da2899SCharles.Forsyth Tk_pointer(void *a)
32137da2899SCharles.Forsyth {
32237da2899SCharles.Forsyth static int buttonr[] = {TkButton1R, TkButton2R, TkButton3R, TkButton4R, TkButton5R, TkButton6R};
32337da2899SCharles.Forsyth static int buttonp[] = {TkButton1P, TkButton2P, TkButton3P, TkButton4P, TkButton5P, TkButton6P};
32437da2899SCharles.Forsyth Tk *fw, *target, *dest, *ent;
32537da2899SCharles.Forsyth TkMouse m;
32637da2899SCharles.Forsyth TkCtxt *c;
32737da2899SCharles.Forsyth TkTop *t, *ot;
32837da2899SCharles.Forsyth int d, dtype, etype;
32937da2899SCharles.Forsyth F_Tk_pointer *f = a;
33037da2899SCharles.Forsyth int b, lastb, inside;
33137da2899SCharles.Forsyth
33237da2899SCharles.Forsyth t = (TkTop*)f->t;
33337da2899SCharles.Forsyth if(t == H || D2H(t)->t != fakeTkTop)
33437da2899SCharles.Forsyth return;
33537da2899SCharles.Forsyth
33637da2899SCharles.Forsyth c = t->ctxt;
33737da2899SCharles.Forsyth
33837da2899SCharles.Forsyth /* ignore no-button-motion for emulated stylus input */
33937da2899SCharles.Forsyth if(tkstylus && c->mstate.b == 0 && (f->p.buttons&0x1f)==0)
34037da2899SCharles.Forsyth return;
34137da2899SCharles.Forsyth
34237da2899SCharles.Forsyth lockctxt(c);
34337da2899SCharles.Forsyth //if (f->p.buttons != 0 || c->mstate.b != 0)
34437da2899SCharles.Forsyth //print("tkmouse %d [%d %d], focused %d[%s], grab %s, entered %s\n",
34537da2899SCharles.Forsyth // f->p.buttons, f->p.xy.x, f->p.xy.y, c->focused, tkname(c->mfocus), tkname(c->mgrab), tkname(c->entered));
34637da2899SCharles.Forsyth /*
34737da2899SCharles.Forsyth * target is the widget that we're deliver the mouse event to.
34837da2899SCharles.Forsyth * inside is true if the mouse point is located inside target.
34937da2899SCharles.Forsyth */
35037da2899SCharles.Forsyth inside = 1;
35137da2899SCharles.Forsyth if (c->mgrab != nil && (c->mgrab->flag & Tknograb)) {
35237da2899SCharles.Forsyth fw = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 1);
35337da2899SCharles.Forsyth if (fw != nil && (fw->flag & Tknograb))
35437da2899SCharles.Forsyth target = fw;
35537da2899SCharles.Forsyth else {
35637da2899SCharles.Forsyth target = c->mgrab;
35737da2899SCharles.Forsyth inside = 0;
35837da2899SCharles.Forsyth }
35937da2899SCharles.Forsyth } else if (c->focused) {
36037da2899SCharles.Forsyth if (c->mfocus != nil) {
36137da2899SCharles.Forsyth fw = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 1);
36237da2899SCharles.Forsyth if (fw != c->mfocus)
36337da2899SCharles.Forsyth inside = 0;
36437da2899SCharles.Forsyth }
36537da2899SCharles.Forsyth target = c->mfocus;
36637da2899SCharles.Forsyth } else if (c->mgrab != nil && (c->mgrab->flag & Tkdisabled) == 0) {
36737da2899SCharles.Forsyth /*
36837da2899SCharles.Forsyth * XXX this isn't quite right, as perhaps we should do a tkinwindow()
36937da2899SCharles.Forsyth * (below the grab).
37037da2899SCharles.Forsyth * so that events to containers underneath the grab arrive
37137da2899SCharles.Forsyth * via the containers (as is usual)
37237da2899SCharles.Forsyth */
37337da2899SCharles.Forsyth fw = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 1);
37437da2899SCharles.Forsyth if (fw != nil && tkdescendant(c->mgrab, fw))
37537da2899SCharles.Forsyth target = fw;
37637da2899SCharles.Forsyth else {
37737da2899SCharles.Forsyth target = c->mgrab;
37837da2899SCharles.Forsyth inside = 0;
37937da2899SCharles.Forsyth }
38037da2899SCharles.Forsyth } else
38137da2899SCharles.Forsyth target = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 0);
38237da2899SCharles.Forsyth
38337da2899SCharles.Forsyth lastb = c->mstate.b;
38437da2899SCharles.Forsyth c->mstate.x = f->p.xy.x;
38537da2899SCharles.Forsyth c->mstate.y = f->p.xy.y;
38637da2899SCharles.Forsyth c->mstate.b = f->p.buttons & 0x1f; /* Just the buttons */
38737da2899SCharles.Forsyth m = c->mstate;
38837da2899SCharles.Forsyth
38937da2899SCharles.Forsyth /* XXX if the mouse is being moved with the buttons held down
39037da2899SCharles.Forsyth * and we've no mfocus and no mgrab then ignore
39137da2899SCharles.Forsyth * the event as our original target has gone away (or never existed)
39237da2899SCharles.Forsyth */
39337da2899SCharles.Forsyth if (lastb && m.b && !c->focused && c->mgrab == nil)
39437da2899SCharles.Forsyth target = nil;
39537da2899SCharles.Forsyth
39637da2899SCharles.Forsyth if (target != c->entered || (c->entered != nil && !inside)) {
39737da2899SCharles.Forsyth if (c->entered != nil) {
39837da2899SCharles.Forsyth fw = c->entered;
39937da2899SCharles.Forsyth c->entered = nil;
40037da2899SCharles.Forsyth tkdeliver(fw, TkLeave, nil);
40137da2899SCharles.Forsyth if (target == nil || fw->env->top != target->env->top)
40237da2899SCharles.Forsyth tkupdate(fw->env->top);
40337da2899SCharles.Forsyth }
40437da2899SCharles.Forsyth if (inside) {
40537da2899SCharles.Forsyth c->entered = target;
40637da2899SCharles.Forsyth tkdeliver(target, TkEnter, &m);
40737da2899SCharles.Forsyth }
40837da2899SCharles.Forsyth }
40937da2899SCharles.Forsyth
41037da2899SCharles.Forsyth dest = nil;
41137da2899SCharles.Forsyth if (target != nil) {
41237da2899SCharles.Forsyth etype = 0;
41337da2899SCharles.Forsyth dtype = 0;
41437da2899SCharles.Forsyth if(f->p.buttons & (1<<8)) /* Double */
41537da2899SCharles.Forsyth dtype = TkDouble;
41637da2899SCharles.Forsyth
41737da2899SCharles.Forsyth d = lastb ^ m.b;
41837da2899SCharles.Forsyth if (d) {
41937da2899SCharles.Forsyth /* cancel any autorepeat, notifying existing client */
42037da2899SCharles.Forsyth tkrepeat(nil, nil, nil, 0, 0);
42137da2899SCharles.Forsyth if (d & ~lastb & 1) /* button 1 potentially takes the focus */
42237da2899SCharles.Forsyth tkdeliver(target, TkTakefocus|TkButton1P, &m);
42337da2899SCharles.Forsyth }
42437da2899SCharles.Forsyth for(b=0; b<nelem(buttonp); b++){
42537da2899SCharles.Forsyth if(d & (1<<b)){
42637da2899SCharles.Forsyth etype = buttonr[b];
42737da2899SCharles.Forsyth if(m.b & (1<<b))
42837da2899SCharles.Forsyth etype = buttonp[b]|dtype;
42937da2899SCharles.Forsyth dest = tkdeliver(target, etype, &m);
43037da2899SCharles.Forsyth }
43137da2899SCharles.Forsyth }
43237da2899SCharles.Forsyth if(tkstylus && m.b==0) {
43337da2899SCharles.Forsyth if ((ent = c->entered) != nil) {
43437da2899SCharles.Forsyth c->entered = nil;
43537da2899SCharles.Forsyth ot = ent->env->top;
43637da2899SCharles.Forsyth tkdeliver(ent, TkLeave, nil);
43737da2899SCharles.Forsyth if (ot != target->env->top)
43837da2899SCharles.Forsyth tkupdate(ot);
43937da2899SCharles.Forsyth }
44037da2899SCharles.Forsyth } else if(etype == 0) {
44137da2899SCharles.Forsyth etype = TkMotion;
44237da2899SCharles.Forsyth for(b = 0; b<nelem(buttonp); b++)
44337da2899SCharles.Forsyth if (m.b & (1<<b))
44437da2899SCharles.Forsyth etype |= buttonp[b];
44537da2899SCharles.Forsyth tkdeliver(target, etype, &m);
44637da2899SCharles.Forsyth }
44737da2899SCharles.Forsyth if (m.b != 0) {
44837da2899SCharles.Forsyth if (lastb == 0 && !c->focused) { /* (some deliver might have grabbed it...) */
44937da2899SCharles.Forsyth if (dest == nil)
45037da2899SCharles.Forsyth dest = target;
45137da2899SCharles.Forsyth if ((dest->flag & Tknograb) == 0) {
45237da2899SCharles.Forsyth c->focused = 1;
45337da2899SCharles.Forsyth c->mfocus = dest;
45437da2899SCharles.Forsyth }
45537da2899SCharles.Forsyth }
45637da2899SCharles.Forsyth } else {
45737da2899SCharles.Forsyth c->focused = 0;
45837da2899SCharles.Forsyth c->mfocus = nil;
45937da2899SCharles.Forsyth if (lastb != 0)
46037da2899SCharles.Forsyth tkenterleave(t);
46137da2899SCharles.Forsyth }
46237da2899SCharles.Forsyth tkupdate(target->env->top);
46337da2899SCharles.Forsyth } else if (c->focused && m.b == 0) {
46437da2899SCharles.Forsyth c->focused = 0;
46537da2899SCharles.Forsyth tkenterleave(t);
46637da2899SCharles.Forsyth }
46737da2899SCharles.Forsyth unlockctxt(c);
46837da2899SCharles.Forsyth }
46937da2899SCharles.Forsyth
47037da2899SCharles.Forsyth void
Tk_keyboard(void * a)47137da2899SCharles.Forsyth Tk_keyboard(void *a)
47237da2899SCharles.Forsyth {
47337da2899SCharles.Forsyth Tk *grab;
47437da2899SCharles.Forsyth TkTop *t;
47537da2899SCharles.Forsyth TkCtxt *c;
47637da2899SCharles.Forsyth F_Tk_keyboard *f = a;
47737da2899SCharles.Forsyth
47837da2899SCharles.Forsyth t = (TkTop*)f->t;
47937da2899SCharles.Forsyth if(t == H || D2H(t)->t != fakeTkTop)
48037da2899SCharles.Forsyth return;
48137da2899SCharles.Forsyth c = t->ctxt;
48237da2899SCharles.Forsyth if (c == nil)
48337da2899SCharles.Forsyth return;
48437da2899SCharles.Forsyth lockctxt(c);
48537da2899SCharles.Forsyth if (c->tkmenu != nil)
48637da2899SCharles.Forsyth grab = c->tkmenu;
48737da2899SCharles.Forsyth else
48837da2899SCharles.Forsyth grab = c->tkkeygrab;
48937da2899SCharles.Forsyth if(grab == nil){
49037da2899SCharles.Forsyth unlockctxt(c);
49137da2899SCharles.Forsyth return;
49237da2899SCharles.Forsyth }
49337da2899SCharles.Forsyth
49437da2899SCharles.Forsyth t = grab->env->top;
49537da2899SCharles.Forsyth tkdeliver(grab, TkKey|TKKEY(f->key), nil);
49637da2899SCharles.Forsyth tkupdate(t);
49737da2899SCharles.Forsyth unlockctxt(c);
49837da2899SCharles.Forsyth }
49937da2899SCharles.Forsyth
50037da2899SCharles.Forsyth TkVar*
tkmkvar(TkTop * t,char * name,int type)50137da2899SCharles.Forsyth tkmkvar(TkTop *t, char *name, int type)
50237da2899SCharles.Forsyth {
50337da2899SCharles.Forsyth TkVar *v;
50437da2899SCharles.Forsyth
50537da2899SCharles.Forsyth for(v = t->vars; v; v = v->link)
50637da2899SCharles.Forsyth if(strcmp(v->name, name) == 0)
50737da2899SCharles.Forsyth return v;
50837da2899SCharles.Forsyth
50937da2899SCharles.Forsyth if(type == 0)
51037da2899SCharles.Forsyth return nil;
51137da2899SCharles.Forsyth
51237da2899SCharles.Forsyth v = malloc(sizeof(TkVar)+strlen(name)+1);
51337da2899SCharles.Forsyth if(v == nil)
51437da2899SCharles.Forsyth return nil;
51537da2899SCharles.Forsyth strcpy(v->name, name);
51637da2899SCharles.Forsyth v->link = t->vars;
51737da2899SCharles.Forsyth t->vars = v;
51837da2899SCharles.Forsyth v->type = type;
51937da2899SCharles.Forsyth v->value = nil;
52037da2899SCharles.Forsyth if(type == TkVchan)
52137da2899SCharles.Forsyth v->value = H;
52237da2899SCharles.Forsyth return v;
52337da2899SCharles.Forsyth }
52437da2899SCharles.Forsyth
52537da2899SCharles.Forsyth void
tkfreevar(TkTop * t,char * name,int swept)52637da2899SCharles.Forsyth tkfreevar(TkTop *t, char *name, int swept)
52737da2899SCharles.Forsyth {
52837da2899SCharles.Forsyth TkVar **l, *p;
52937da2899SCharles.Forsyth
53037da2899SCharles.Forsyth if(name == nil)
53137da2899SCharles.Forsyth return;
53237da2899SCharles.Forsyth l = &t->vars;
53337da2899SCharles.Forsyth for(p = *l; p != nil; p = p->link) {
53437da2899SCharles.Forsyth if(strcmp(p->name, name) == 0) {
53537da2899SCharles.Forsyth *l = p->link;
53637da2899SCharles.Forsyth switch(p->type) {
53737da2899SCharles.Forsyth default:
53837da2899SCharles.Forsyth free(p->value);
53937da2899SCharles.Forsyth break;
54037da2899SCharles.Forsyth case TkVchan:
54137da2899SCharles.Forsyth if(!swept)
54237da2899SCharles.Forsyth destroy(p->value);
54337da2899SCharles.Forsyth break;
54437da2899SCharles.Forsyth }
54537da2899SCharles.Forsyth free(p);
54637da2899SCharles.Forsyth return;
54737da2899SCharles.Forsyth }
54837da2899SCharles.Forsyth l = &p->link;
54937da2899SCharles.Forsyth }
55037da2899SCharles.Forsyth }
55137da2899SCharles.Forsyth
55237da2899SCharles.Forsyth void
Tk_namechan(void * a)55337da2899SCharles.Forsyth Tk_namechan(void *a)
55437da2899SCharles.Forsyth {
55537da2899SCharles.Forsyth Heap *h;
55637da2899SCharles.Forsyth TkVar *v;
55737da2899SCharles.Forsyth TkTop *t;
55837da2899SCharles.Forsyth char *name;
55937da2899SCharles.Forsyth F_Tk_namechan *f = a;
56037da2899SCharles.Forsyth
56137da2899SCharles.Forsyth t = (TkTop*)f->t;
56237da2899SCharles.Forsyth if(t == H || D2H(t)->t != fakeTkTop) {
56337da2899SCharles.Forsyth retstr(TkNotop, f->ret);
56437da2899SCharles.Forsyth return;
56537da2899SCharles.Forsyth }
56637da2899SCharles.Forsyth if(f->c == H) {
56737da2899SCharles.Forsyth retstr("nil channel", f->ret);
56837da2899SCharles.Forsyth return;
56937da2899SCharles.Forsyth }
57037da2899SCharles.Forsyth name = string2c(f->n);
57137da2899SCharles.Forsyth if(name[0] == '\0') {
57237da2899SCharles.Forsyth retstr(TkBadvl, f->ret);
57337da2899SCharles.Forsyth return;
57437da2899SCharles.Forsyth }
57537da2899SCharles.Forsyth
57637da2899SCharles.Forsyth lockctxt(t->ctxt);
57737da2899SCharles.Forsyth v = tkmkvar(t, name, TkVchan);
57837da2899SCharles.Forsyth if(v == nil) {
57937da2899SCharles.Forsyth unlockctxt(t->ctxt);
58037da2899SCharles.Forsyth retstr(TkNomem, f->ret);
58137da2899SCharles.Forsyth return;
58237da2899SCharles.Forsyth }
58337da2899SCharles.Forsyth if(v->type != TkVchan) {
58437da2899SCharles.Forsyth unlockctxt(t->ctxt);
58537da2899SCharles.Forsyth retstr(TkNotvt, f->ret);
58637da2899SCharles.Forsyth return;
58737da2899SCharles.Forsyth }
58837da2899SCharles.Forsyth destroy(v->value);
58937da2899SCharles.Forsyth v->value = f->c;
59037da2899SCharles.Forsyth unlockctxt(t->ctxt);
59137da2899SCharles.Forsyth h = D2H(v->value);
59237da2899SCharles.Forsyth h->ref++;
59337da2899SCharles.Forsyth Setmark(h);
59437da2899SCharles.Forsyth retstr("", f->ret);
59537da2899SCharles.Forsyth }
59637da2899SCharles.Forsyth
59737da2899SCharles.Forsyth void
Tk_quote(void * a)59837da2899SCharles.Forsyth Tk_quote(void *a)
59937da2899SCharles.Forsyth {
60037da2899SCharles.Forsyth String *s, *ns;
60137da2899SCharles.Forsyth F_Tk_quote *f;
60237da2899SCharles.Forsyth void *r;
60337da2899SCharles.Forsyth int c, i, need, len, userune, last, n;
60437da2899SCharles.Forsyth Rune *sr;
60537da2899SCharles.Forsyth char *sc;
60637da2899SCharles.Forsyth
60737da2899SCharles.Forsyth f = a;
60837da2899SCharles.Forsyth
60937da2899SCharles.Forsyth r = *f->ret;
61037da2899SCharles.Forsyth *f->ret = H;
61137da2899SCharles.Forsyth destroy(r);
61237da2899SCharles.Forsyth
61337da2899SCharles.Forsyth s = f->s;
61437da2899SCharles.Forsyth if(s == H){
61537da2899SCharles.Forsyth retstr("{}", f->ret);
61637da2899SCharles.Forsyth return;
61737da2899SCharles.Forsyth }
61837da2899SCharles.Forsyth len = s->len;
61937da2899SCharles.Forsyth userune = 0;
62037da2899SCharles.Forsyth if(len < 0) {
62137da2899SCharles.Forsyth len = -len;
62237da2899SCharles.Forsyth userune = 1;
62337da2899SCharles.Forsyth }
62437da2899SCharles.Forsyth need = len+2;
62537da2899SCharles.Forsyth for(i = 0; i < len; i++) {
62637da2899SCharles.Forsyth c = userune? s->Srune[i]: s->Sascii[i];
62737da2899SCharles.Forsyth if(c == '{' || c == '}' || c == '\\')
62837da2899SCharles.Forsyth need++;
62937da2899SCharles.Forsyth }
63037da2899SCharles.Forsyth if(userune) {
63137da2899SCharles.Forsyth ns = newrunes(need);
63237da2899SCharles.Forsyth sr = ns->Srune;
63337da2899SCharles.Forsyth *sr++ = '{';
63437da2899SCharles.Forsyth last = 0;
63537da2899SCharles.Forsyth for(i = 0;; i++) {
63637da2899SCharles.Forsyth if(i >= len || (c = s->Srune[i]) == '{' || c == '}' || c == '\\'){
63737da2899SCharles.Forsyth n = i-last;
63837da2899SCharles.Forsyth if(n) {
63937da2899SCharles.Forsyth memmove(sr, &s->Srune[last], n*sizeof(Rune));
64037da2899SCharles.Forsyth sr += n;
64137da2899SCharles.Forsyth }
64237da2899SCharles.Forsyth if(i >= len)
64337da2899SCharles.Forsyth break;
64437da2899SCharles.Forsyth *sr++ = '\\';
64537da2899SCharles.Forsyth last = i;
64637da2899SCharles.Forsyth }
64737da2899SCharles.Forsyth }
64837da2899SCharles.Forsyth *sr = '}';
64937da2899SCharles.Forsyth } else {
65037da2899SCharles.Forsyth ns = newstring(need);
65137da2899SCharles.Forsyth sc = ns->Sascii;
65237da2899SCharles.Forsyth *sc++ = '{';
65337da2899SCharles.Forsyth last = 0;
65437da2899SCharles.Forsyth for(i = 0;; i++) {
65537da2899SCharles.Forsyth if(i >= len || (c = s->Sascii[i]) == '{' || c == '}' || c == '\\'){
65637da2899SCharles.Forsyth n = i-last;
65737da2899SCharles.Forsyth if(n) {
65837da2899SCharles.Forsyth memmove(sc, &s->Sascii[last], n);
65937da2899SCharles.Forsyth sc += n;
66037da2899SCharles.Forsyth }
66137da2899SCharles.Forsyth if(i >= len)
66237da2899SCharles.Forsyth break;
66337da2899SCharles.Forsyth *sc++ = '\\';
66437da2899SCharles.Forsyth last = i;
66537da2899SCharles.Forsyth }
66637da2899SCharles.Forsyth }
66737da2899SCharles.Forsyth *sc= '}';
66837da2899SCharles.Forsyth }
66937da2899SCharles.Forsyth *f->ret = ns;
67037da2899SCharles.Forsyth }
67137da2899SCharles.Forsyth
67237da2899SCharles.Forsyth static void
tkreplimg(TkTop * t,Draw_Image * f,Draw_Image * m,Image ** ximg)67337da2899SCharles.Forsyth tkreplimg(TkTop *t, Draw_Image *f, Draw_Image *m, Image **ximg)
67437da2899SCharles.Forsyth {
67537da2899SCharles.Forsyth Display *d;
67637da2899SCharles.Forsyth Image *cimg, *cmask, *new;
67737da2899SCharles.Forsyth
67837da2899SCharles.Forsyth cimg = lookupimage(f);
67937da2899SCharles.Forsyth d = t->display;
68037da2899SCharles.Forsyth if(cimg == nil || cimg->screen != nil || cimg->display != d)
68137da2899SCharles.Forsyth return;
68237da2899SCharles.Forsyth cmask = lookupimage(m);
68337da2899SCharles.Forsyth if(cmask != nil && (cmask->screen != nil || cmask->display != d))
68437da2899SCharles.Forsyth return;
68537da2899SCharles.Forsyth
68637da2899SCharles.Forsyth if (cmask == nil)
68737da2899SCharles.Forsyth new = allocimage(d, Rect(0, 0, Dx(cimg->r), Dy(cimg->r)), cimg->chan, 0, DNofill);
68837da2899SCharles.Forsyth else {
68937da2899SCharles.Forsyth if(cmask->screen != nil || cmask->display != d)
69037da2899SCharles.Forsyth return;
69137da2899SCharles.Forsyth new = allocimage(d, Rect(0, 0, Dx(cimg->r), Dy(cimg->r)), RGBA32, 0, DTransparent);
69237da2899SCharles.Forsyth }
69337da2899SCharles.Forsyth if(new == nil)
69437da2899SCharles.Forsyth return;
69537da2899SCharles.Forsyth draw(new, new->r, cimg, cmask, cimg->r.min);
69637da2899SCharles.Forsyth if(tkwiretap != nil)
69737da2899SCharles.Forsyth tkwiretap(t, "replimg", nil, cimg, &cimg->r);
69837da2899SCharles.Forsyth if(*ximg != nil)
69937da2899SCharles.Forsyth freeimage(*ximg);
70037da2899SCharles.Forsyth *ximg = new;
70137da2899SCharles.Forsyth }
70237da2899SCharles.Forsyth
70337da2899SCharles.Forsyth static char*
tkaddpanelimage(TkTop * t,Draw_Image * di,Image ** i)70437da2899SCharles.Forsyth tkaddpanelimage(TkTop *t, Draw_Image *di, Image **i)
70537da2899SCharles.Forsyth {
70637da2899SCharles.Forsyth TkPanelimage *pi;
70737da2899SCharles.Forsyth
70837da2899SCharles.Forsyth if (di == H) {
70937da2899SCharles.Forsyth *i = 0;
71037da2899SCharles.Forsyth return nil;
71137da2899SCharles.Forsyth }
71237da2899SCharles.Forsyth
71337da2899SCharles.Forsyth *i = lookupimage(di);
71437da2899SCharles.Forsyth if (*i == nil || (*i)->display != t->display)
71537da2899SCharles.Forsyth return TkNotwm;
71637da2899SCharles.Forsyth
71737da2899SCharles.Forsyth for (pi = t->panelimages; pi != nil; pi = pi->link) {
71837da2899SCharles.Forsyth if (pi->image == di) {
71937da2899SCharles.Forsyth pi->ref++;
72037da2899SCharles.Forsyth return nil;
72137da2899SCharles.Forsyth }
72237da2899SCharles.Forsyth }
72337da2899SCharles.Forsyth
72437da2899SCharles.Forsyth pi = malloc(sizeof(TkPanelimage));
72537da2899SCharles.Forsyth if (pi == nil)
72637da2899SCharles.Forsyth return TkNomem;
72737da2899SCharles.Forsyth pi->image = di;
72837da2899SCharles.Forsyth D2H(di)->ref++;
72937da2899SCharles.Forsyth pi->ref = 1;
73037da2899SCharles.Forsyth pi->link = t->panelimages;
73137da2899SCharles.Forsyth t->panelimages = pi;
73237da2899SCharles.Forsyth return nil;
73337da2899SCharles.Forsyth }
73437da2899SCharles.Forsyth
73537da2899SCharles.Forsyth void
tkdelpanelimage(TkTop * t,Image * i)73637da2899SCharles.Forsyth tkdelpanelimage(TkTop *t, Image *i)
73737da2899SCharles.Forsyth {
73837da2899SCharles.Forsyth TkPanelimage *pi, *prev;
73937da2899SCharles.Forsyth int locked;
74037da2899SCharles.Forsyth
74137da2899SCharles.Forsyth if (i == nil)
74237da2899SCharles.Forsyth return;
74337da2899SCharles.Forsyth
74437da2899SCharles.Forsyth prev = nil;
74537da2899SCharles.Forsyth for (pi = t->panelimages; pi != nil; pi = pi->link) {
74637da2899SCharles.Forsyth if (lookupimage(pi->image) == i)
74737da2899SCharles.Forsyth break;
74837da2899SCharles.Forsyth prev = pi;
74937da2899SCharles.Forsyth }
75037da2899SCharles.Forsyth if (pi == nil || --pi->ref > 0)
75137da2899SCharles.Forsyth return;
75237da2899SCharles.Forsyth if (prev)
75337da2899SCharles.Forsyth prev->link = pi->link;
75437da2899SCharles.Forsyth else
75537da2899SCharles.Forsyth t->panelimages = pi->link;
75637da2899SCharles.Forsyth if (D2H(pi->image)->ref == 1) { /* don't bother locking if it's not going away */
75737da2899SCharles.Forsyth locked = lockdisplay(t->display);
75837da2899SCharles.Forsyth destroy(pi->image);
75937da2899SCharles.Forsyth if (locked)
76037da2899SCharles.Forsyth unlockdisplay(t->display);
76137da2899SCharles.Forsyth }
76237da2899SCharles.Forsyth
76337da2899SCharles.Forsyth free(pi);
76437da2899SCharles.Forsyth }
76537da2899SCharles.Forsyth
76637da2899SCharles.Forsyth void
Tk_putimage(void * a)76737da2899SCharles.Forsyth Tk_putimage(void *a)
76837da2899SCharles.Forsyth {
76937da2899SCharles.Forsyth TkTop *t;
77037da2899SCharles.Forsyth TkImg *tki;
77137da2899SCharles.Forsyth Image *i, *m, *oldi, *oldm;
77237da2899SCharles.Forsyth int locked, found, reqid, n;
77337da2899SCharles.Forsyth char *words[2];
77437da2899SCharles.Forsyth Display *d;
77537da2899SCharles.Forsyth F_Tk_putimage *f;
77637da2899SCharles.Forsyth void *r;
77737da2899SCharles.Forsyth char *name, *e;
77837da2899SCharles.Forsyth Tk *tk;
77937da2899SCharles.Forsyth
78037da2899SCharles.Forsyth f = a;
78137da2899SCharles.Forsyth
78237da2899SCharles.Forsyth r = *f->ret;
78337da2899SCharles.Forsyth *f->ret = H;
78437da2899SCharles.Forsyth destroy(r);
78537da2899SCharles.Forsyth
78637da2899SCharles.Forsyth t = (TkTop*)f->t;
78737da2899SCharles.Forsyth if(t == H || D2H(t)->t != fakeTkTop) {
78837da2899SCharles.Forsyth retstr(TkNotop, f->ret);
78937da2899SCharles.Forsyth return;
79037da2899SCharles.Forsyth }
79137da2899SCharles.Forsyth
79237da2899SCharles.Forsyth if(f->i == H) {
79337da2899SCharles.Forsyth retstr(TkBadvl, f->ret);
79437da2899SCharles.Forsyth return;
79537da2899SCharles.Forsyth }
79637da2899SCharles.Forsyth
79737da2899SCharles.Forsyth name = string2c(f->name);
79837da2899SCharles.Forsyth lockctxt(t->ctxt);
79937da2899SCharles.Forsyth e = nil;
80037da2899SCharles.Forsyth found = 0;
80137da2899SCharles.Forsyth if(name[0] == '.'){
80237da2899SCharles.Forsyth n = getfields(name, words, nelem(words), 1, " ");
80337da2899SCharles.Forsyth reqid = -1;
80437da2899SCharles.Forsyth if(n > 1){
80537da2899SCharles.Forsyth reqid = atoi(words[1]);
80637da2899SCharles.Forsyth name = words[0];
80737da2899SCharles.Forsyth }
80837da2899SCharles.Forsyth if((tk = tklook(t, name, 0)) != nil){
80937da2899SCharles.Forsyth if(tk->type == TKchoicebutton){
81037da2899SCharles.Forsyth tk = tkfindchoicemenu(tk);
81137da2899SCharles.Forsyth if(tk == nil)
81237da2899SCharles.Forsyth goto Error;
81337da2899SCharles.Forsyth }
81437da2899SCharles.Forsyth if(tk->type == TKframe || tk->type == TKmenu){
81537da2899SCharles.Forsyth if((tk->flag & Tkwindow) == 0){
81637da2899SCharles.Forsyth e = TkNotwm;
81737da2899SCharles.Forsyth goto Error;
81837da2899SCharles.Forsyth }
81937da2899SCharles.Forsyth e = tkputwinimage(tk, f->i, reqid);
82037da2899SCharles.Forsyth found = 1;
82137da2899SCharles.Forsyth } else
82237da2899SCharles.Forsyth if(tk->type == TKpanel){
82337da2899SCharles.Forsyth if(n > 1){
82437da2899SCharles.Forsyth e = TkBadvl;
82537da2899SCharles.Forsyth goto Error;
82637da2899SCharles.Forsyth }
82737da2899SCharles.Forsyth e = tkaddpanelimage(t, f->i, &i);
82837da2899SCharles.Forsyth if(e != nil)
82937da2899SCharles.Forsyth goto Error;
83037da2899SCharles.Forsyth e = tkaddpanelimage(t, f->m, &m);
83137da2899SCharles.Forsyth if(e != nil){
83237da2899SCharles.Forsyth tkdelpanelimage(t, i);
83337da2899SCharles.Forsyth goto Error;
83437da2899SCharles.Forsyth }
83537da2899SCharles.Forsyth tkgetpanelimage(tk, &oldi, &oldm);
83637da2899SCharles.Forsyth tkdelpanelimage(t, oldi);
83737da2899SCharles.Forsyth tkdelpanelimage(t, oldm);
83837da2899SCharles.Forsyth tksetpanelimage(tk, i, m);
83937da2899SCharles.Forsyth tkdirty(tk);
84037da2899SCharles.Forsyth found = 1;
84137da2899SCharles.Forsyth }
84237da2899SCharles.Forsyth }
84337da2899SCharles.Forsyth }
84437da2899SCharles.Forsyth if(!found){
84537da2899SCharles.Forsyth /* XXX perhaps we shouldn't ever do this if name begins with '.'? */
84637da2899SCharles.Forsyth tki = tkname2img(t, name);
84737da2899SCharles.Forsyth if(tki == nil) {
84837da2899SCharles.Forsyth e = TkBadvl;
84937da2899SCharles.Forsyth goto Error;
85037da2899SCharles.Forsyth }
85137da2899SCharles.Forsyth
85237da2899SCharles.Forsyth d = t->display;
85337da2899SCharles.Forsyth locked = lockdisplay(d);
85437da2899SCharles.Forsyth tkreplimg(t, f->i, f->m, &tki->img);
85537da2899SCharles.Forsyth if(locked)
85637da2899SCharles.Forsyth unlockdisplay(d);
85737da2899SCharles.Forsyth
85837da2899SCharles.Forsyth tksizeimage(t->root, tki);
85937da2899SCharles.Forsyth }
86037da2899SCharles.Forsyth Error:
86137da2899SCharles.Forsyth unlockctxt(t->ctxt);
86237da2899SCharles.Forsyth if(e != nil)
86337da2899SCharles.Forsyth retstr(e, f->ret);
86437da2899SCharles.Forsyth return;
86537da2899SCharles.Forsyth }
86637da2899SCharles.Forsyth
86737da2899SCharles.Forsyth Draw_Image*
tkimgcopy(TkTop * t,Image * cimg)86837da2899SCharles.Forsyth tkimgcopy(TkTop *t, Image *cimg)
86937da2899SCharles.Forsyth {
87037da2899SCharles.Forsyth Image *new;
87137da2899SCharles.Forsyth Display *dp;
87237da2899SCharles.Forsyth Draw_Image *i;
87337da2899SCharles.Forsyth
87437da2899SCharles.Forsyth if(cimg == nil)
87537da2899SCharles.Forsyth return H;
87637da2899SCharles.Forsyth
87737da2899SCharles.Forsyth dp = t->display;
87837da2899SCharles.Forsyth new = allocimage(dp, cimg->r, cimg->chan, cimg->repl, DNofill);
87937da2899SCharles.Forsyth if(new == nil)
88037da2899SCharles.Forsyth return H;
88137da2899SCharles.Forsyth new->clipr = cimg->clipr;
88237da2899SCharles.Forsyth
88337da2899SCharles.Forsyth drawop(new, new->r, cimg, nil, cimg->r.min, S);
88437da2899SCharles.Forsyth if(tkwiretap != nil)
88537da2899SCharles.Forsyth tkwiretap(t, "imgcopy", nil, cimg, &cimg->r);
88637da2899SCharles.Forsyth
88737da2899SCharles.Forsyth i = mkdrawimage(new, H, t->dd, nil);
88837da2899SCharles.Forsyth if(i == H)
88937da2899SCharles.Forsyth freeimage(new);
89037da2899SCharles.Forsyth
89137da2899SCharles.Forsyth return i;
89237da2899SCharles.Forsyth }
89337da2899SCharles.Forsyth
89437da2899SCharles.Forsyth void
Tk_getimage(void * a)89537da2899SCharles.Forsyth Tk_getimage(void *a)
89637da2899SCharles.Forsyth {
89737da2899SCharles.Forsyth Tk *tk;
89837da2899SCharles.Forsyth char *n;
89937da2899SCharles.Forsyth TkImg *i;
90037da2899SCharles.Forsyth TkTop *t;
90137da2899SCharles.Forsyth int locked;
90237da2899SCharles.Forsyth Display *d;
90337da2899SCharles.Forsyth F_Tk_getimage *f;
90437da2899SCharles.Forsyth void *r;
90537da2899SCharles.Forsyth void (*getimgs)(Tk*, Image**, Image**);
90637da2899SCharles.Forsyth Image *image, *mask;
90737da2899SCharles.Forsyth
90837da2899SCharles.Forsyth f = a;
90937da2899SCharles.Forsyth
91037da2899SCharles.Forsyth r = f->ret->t0;
91137da2899SCharles.Forsyth f->ret->t0 = H;
91237da2899SCharles.Forsyth destroy(r);
91337da2899SCharles.Forsyth r = f->ret->t1;
91437da2899SCharles.Forsyth f->ret->t1 = H;
91537da2899SCharles.Forsyth destroy(r);
91637da2899SCharles.Forsyth r = f->ret->t2;
91737da2899SCharles.Forsyth f->ret->t2 = H;
91837da2899SCharles.Forsyth destroy(r);
91937da2899SCharles.Forsyth
92037da2899SCharles.Forsyth t = (TkTop*)f->t;
92137da2899SCharles.Forsyth if(t == H || D2H(t)->t != fakeTkTop) {
92237da2899SCharles.Forsyth retstr(TkNotop, &f->ret->t2);
92337da2899SCharles.Forsyth return;
92437da2899SCharles.Forsyth }
92537da2899SCharles.Forsyth d = t->ctxt->display;
92637da2899SCharles.Forsyth n = string2c(f->name);
92737da2899SCharles.Forsyth lockctxt(t->ctxt);
92837da2899SCharles.Forsyth i = tkname2img(t, n);
92937da2899SCharles.Forsyth if (i != nil) {
93037da2899SCharles.Forsyth image = i->img;
93137da2899SCharles.Forsyth mask = nil;
93237da2899SCharles.Forsyth } else {
93337da2899SCharles.Forsyth tk = tklook(t, n, 0);
93437da2899SCharles.Forsyth if (tk == nil || (getimgs = tkmethod[tk->type]->getimgs) == nil) {
93537da2899SCharles.Forsyth unlockctxt(t->ctxt);
93637da2899SCharles.Forsyth retstr(TkBadvl, &f->ret->t2);
93737da2899SCharles.Forsyth return;
93837da2899SCharles.Forsyth }
93937da2899SCharles.Forsyth getimgs(tk, &image, &mask);
94037da2899SCharles.Forsyth }
94137da2899SCharles.Forsyth locked = lockdisplay(d);
94237da2899SCharles.Forsyth f->ret->t0 = tkimgcopy(t, image);
94337da2899SCharles.Forsyth if (mask != nil)
94437da2899SCharles.Forsyth f->ret->t1 = tkimgcopy(t, mask);
94537da2899SCharles.Forsyth if (locked)
94637da2899SCharles.Forsyth unlockdisplay(d);
94737da2899SCharles.Forsyth unlockctxt(t->ctxt);
94837da2899SCharles.Forsyth }
94937da2899SCharles.Forsyth
95037da2899SCharles.Forsyth void
tkfreetop(Heap * h,int swept)95137da2899SCharles.Forsyth tkfreetop(Heap *h, int swept)
95237da2899SCharles.Forsyth {
95337da2899SCharles.Forsyth TkTop *t;
95437da2899SCharles.Forsyth Tk *f;
95537da2899SCharles.Forsyth TkImg *i, *nexti;
95637da2899SCharles.Forsyth TkVar *v, *nextv;
95737da2899SCharles.Forsyth int wgtype;
95837da2899SCharles.Forsyth void *r;
95937da2899SCharles.Forsyth TkPanelimage *pi, *nextpi;
96037da2899SCharles.Forsyth
96137da2899SCharles.Forsyth t = H2D(TkTop*, h);
96237da2899SCharles.Forsyth lockctxt(t->ctxt);
96337da2899SCharles.Forsyth
96437da2899SCharles.Forsyth if(swept) {
96537da2899SCharles.Forsyth t->di = H;
96637da2899SCharles.Forsyth t->dd = H;
96737da2899SCharles.Forsyth t->wreq = H;
96837da2899SCharles.Forsyth t->wmctxt = H;
96937da2899SCharles.Forsyth }
97037da2899SCharles.Forsyth
97137da2899SCharles.Forsyth t->windows = nil;
97237da2899SCharles.Forsyth
97337da2899SCharles.Forsyth for(f = t->root; f; f = f->siblings) {
97437da2899SCharles.Forsyth f->flag |= Tkdestroy;
97537da2899SCharles.Forsyth tkdeliver(f, TkDestroy, nil);
97637da2899SCharles.Forsyth if(f->destroyed != nil)
97737da2899SCharles.Forsyth f->destroyed(f);
97837da2899SCharles.Forsyth }
97937da2899SCharles.Forsyth
98037da2899SCharles.Forsyth for(f = t->root; f; f = t->root) {
98137da2899SCharles.Forsyth t->root = f->siblings;
98237da2899SCharles.Forsyth if(swept)
98337da2899SCharles.Forsyth f->flag |= Tkswept;
98437da2899SCharles.Forsyth tkfreeobj(f);
98537da2899SCharles.Forsyth }
98637da2899SCharles.Forsyth
98737da2899SCharles.Forsyth for(v = t->vars; v; v = nextv) {
98837da2899SCharles.Forsyth nextv = v->link;
98937da2899SCharles.Forsyth switch(v->type) {
99037da2899SCharles.Forsyth default:
99137da2899SCharles.Forsyth free(v->value);
99237da2899SCharles.Forsyth break;
99337da2899SCharles.Forsyth case TkVchan:
99437da2899SCharles.Forsyth if(!swept)
99537da2899SCharles.Forsyth destroy(v->value);
99637da2899SCharles.Forsyth break;
99737da2899SCharles.Forsyth }
99837da2899SCharles.Forsyth free(v);
99937da2899SCharles.Forsyth }
100037da2899SCharles.Forsyth
100137da2899SCharles.Forsyth for (pi = t->panelimages; pi; pi = nextpi) {
100237da2899SCharles.Forsyth if (!swept)
100337da2899SCharles.Forsyth destroy(pi->image);
100437da2899SCharles.Forsyth nextpi = pi->link;
100537da2899SCharles.Forsyth free(pi);
100637da2899SCharles.Forsyth }
100737da2899SCharles.Forsyth
100837da2899SCharles.Forsyth for(i = t->imgs; i; i = nexti) {
100937da2899SCharles.Forsyth if(i->ref != 1)
101037da2899SCharles.Forsyth abort();
101137da2899SCharles.Forsyth nexti = i->link;
101237da2899SCharles.Forsyth tkimgput(i);
101337da2899SCharles.Forsyth }
101437da2899SCharles.Forsyth /* XXX free images inside widgets */
101537da2899SCharles.Forsyth
101637da2899SCharles.Forsyth for(wgtype = 0; wgtype < TKwidgets; wgtype++)
101737da2899SCharles.Forsyth if(t->binds[wgtype])
101837da2899SCharles.Forsyth tkfreebind(t->binds[wgtype]);
101937da2899SCharles.Forsyth
102037da2899SCharles.Forsyth unlockctxt(t->ctxt);
102137da2899SCharles.Forsyth /* XXX should we leave it locked for this bit? */
102237da2899SCharles.Forsyth tkfreectxt(t->ctxt);
102337da2899SCharles.Forsyth if(!swept) {
102437da2899SCharles.Forsyth r = t->di;
102537da2899SCharles.Forsyth t->di = H;
102637da2899SCharles.Forsyth destroy(r);
102737da2899SCharles.Forsyth
102837da2899SCharles.Forsyth r = t->dd;
102937da2899SCharles.Forsyth t->dd = H;
103037da2899SCharles.Forsyth destroy(r);
103137da2899SCharles.Forsyth
103237da2899SCharles.Forsyth r = t->wreq;
103337da2899SCharles.Forsyth t->wreq = H;
103437da2899SCharles.Forsyth destroy(r);
103537da2899SCharles.Forsyth
103637da2899SCharles.Forsyth r = t->wmctxt;
103737da2899SCharles.Forsyth t->wmctxt = H;
103837da2899SCharles.Forsyth destroy(r);
103937da2899SCharles.Forsyth }
104037da2899SCharles.Forsyth }
104137da2899SCharles.Forsyth
104237da2899SCharles.Forsyth static void
tktopimagedptr(TkTop * top,Draw_Image * di)104337da2899SCharles.Forsyth tktopimagedptr(TkTop *top, Draw_Image *di)
104437da2899SCharles.Forsyth {
104537da2899SCharles.Forsyth if(top->di != H){
104637da2899SCharles.Forsyth destroy(top->di);
104737da2899SCharles.Forsyth top->di = H;
104837da2899SCharles.Forsyth }
104937da2899SCharles.Forsyth if(di == H)
105037da2899SCharles.Forsyth return;
105137da2899SCharles.Forsyth D2H(di)->ref++;
105237da2899SCharles.Forsyth top->di = di;
105337da2899SCharles.Forsyth }
105437da2899SCharles.Forsyth
105537da2899SCharles.Forsyth static void
tkfreewinimage(TkWin * w)105637da2899SCharles.Forsyth tkfreewinimage(TkWin *w)
105737da2899SCharles.Forsyth {
105837da2899SCharles.Forsyth destroy(w->di);
105937da2899SCharles.Forsyth w->image = nil;
106037da2899SCharles.Forsyth w->di = H;
106137da2899SCharles.Forsyth }
106237da2899SCharles.Forsyth
106337da2899SCharles.Forsyth static int
tksetwindrawimage(Tk * tk,Draw_Image * di)106437da2899SCharles.Forsyth tksetwindrawimage(Tk *tk, Draw_Image *di)
106537da2899SCharles.Forsyth {
106637da2899SCharles.Forsyth TkWin *tkw;
106737da2899SCharles.Forsyth char *name;
106837da2899SCharles.Forsyth Image *i;
106937da2899SCharles.Forsyth int locked;
107037da2899SCharles.Forsyth int same;
107137da2899SCharles.Forsyth
107237da2899SCharles.Forsyth tkw = TKobj(TkWin, tk);
107337da2899SCharles.Forsyth
107437da2899SCharles.Forsyth same = tkw->di == di;
107537da2899SCharles.Forsyth if(!same)
107637da2899SCharles.Forsyth if(tkw->image != nil)
107737da2899SCharles.Forsyth destroy(tkw->di);
107837da2899SCharles.Forsyth if(di == H){
107937da2899SCharles.Forsyth tkw->di = H;
108037da2899SCharles.Forsyth tkw->image = nil;
108137da2899SCharles.Forsyth return same;
108237da2899SCharles.Forsyth }
108337da2899SCharles.Forsyth tkw->di = di;
108437da2899SCharles.Forsyth i = lookupimage(di);
108537da2899SCharles.Forsyth tkw->image = i;
108637da2899SCharles.Forsyth
108737da2899SCharles.Forsyth locked = lockdisplay(i->display);
108837da2899SCharles.Forsyth if(originwindow(i, ZP, i->r.min) == -1)
108937da2899SCharles.Forsyth print("tk originwindow failed: %r\n");
109037da2899SCharles.Forsyth di->r = DRECT(i->r);
109137da2899SCharles.Forsyth di->clipr = DRECT(i->clipr);
109237da2899SCharles.Forsyth if(locked)
109337da2899SCharles.Forsyth unlockdisplay(i->display);
109437da2899SCharles.Forsyth
109537da2899SCharles.Forsyth if(!same){
109637da2899SCharles.Forsyth D2H(di)->ref++;
109737da2899SCharles.Forsyth if(tk->name){
109837da2899SCharles.Forsyth name = tk->name->name;
109937da2899SCharles.Forsyth if(name[0] == '.' && name[1] == '\0')
110037da2899SCharles.Forsyth tktopimagedptr(tk->env->top, tkw->di);
110137da2899SCharles.Forsyth }
110237da2899SCharles.Forsyth }
110337da2899SCharles.Forsyth return same;
110437da2899SCharles.Forsyth }
110537da2899SCharles.Forsyth
110637da2899SCharles.Forsyth void
tkdestroywinimage(Tk * tk)110737da2899SCharles.Forsyth tkdestroywinimage(Tk *tk)
110837da2899SCharles.Forsyth {
110937da2899SCharles.Forsyth TkWin *tkw;
111037da2899SCharles.Forsyth TkTop *top;
111137da2899SCharles.Forsyth char *name;
111237da2899SCharles.Forsyth
111337da2899SCharles.Forsyth assert(tk->flag & Tkwindow);
111437da2899SCharles.Forsyth tkw = TKobj(TkWin, tk);
111537da2899SCharles.Forsyth top = tk->env->top;
111637da2899SCharles.Forsyth
111737da2899SCharles.Forsyth if(tkw->image != nil && !(tk->flag & Tkswept))
111837da2899SCharles.Forsyth destroy(tkw->di);
111937da2899SCharles.Forsyth tkw->di = H;
112037da2899SCharles.Forsyth tkw->image = nil;
112137da2899SCharles.Forsyth if(tk->name == nil)
112237da2899SCharles.Forsyth name = tkw->cbname;
112337da2899SCharles.Forsyth else
112437da2899SCharles.Forsyth name = tk->name->name;
112537da2899SCharles.Forsyth if(name[0] == '.' && name[1] == '\0' && !(tk->flag & Tkswept))
112637da2899SCharles.Forsyth tktopimagedptr(top, H);
112737da2899SCharles.Forsyth tkw->reqid++;
112837da2899SCharles.Forsyth tkwreq(top, "delete %s", name);
112937da2899SCharles.Forsyth }
113037da2899SCharles.Forsyth
113137da2899SCharles.Forsyth static char*
tkputwinimage(Tk * tk,Draw_Image * di,int reqid)113237da2899SCharles.Forsyth tkputwinimage(Tk *tk, Draw_Image *di, int reqid)
113337da2899SCharles.Forsyth {
113437da2899SCharles.Forsyth TkWin *tkw;
113537da2899SCharles.Forsyth TkTop *top;
113637da2899SCharles.Forsyth Image *i;
113737da2899SCharles.Forsyth int bw2, prop, resize;
113837da2899SCharles.Forsyth Rectangle req;
113937da2899SCharles.Forsyth
114037da2899SCharles.Forsyth top = tk->env->top;
114137da2899SCharles.Forsyth tkw = TKobj(TkWin, tk);
114237da2899SCharles.Forsyth i = lookupimage(di);
114337da2899SCharles.Forsyth if (i == nil || i->display != top->display)
114437da2899SCharles.Forsyth return TkNotwm;
114537da2899SCharles.Forsyth
114637da2899SCharles.Forsyth if(reqid != -1 && reqid < tkw->reqid)
114737da2899SCharles.Forsyth return "!request out of date";
114837da2899SCharles.Forsyth
114937da2899SCharles.Forsyth bw2 = 2*tk->borderwidth;
115037da2899SCharles.Forsyth req.min.x = tkw->req.x;
115137da2899SCharles.Forsyth req.min.y = tkw->req.y;
115237da2899SCharles.Forsyth req.max.x = req.min.x + tk->act.width + bw2;
115337da2899SCharles.Forsyth req.max.y = req.min.y + tk->act.height + bw2;
115437da2899SCharles.Forsyth
115537da2899SCharles.Forsyth resize = 0;
115637da2899SCharles.Forsyth if(eqrect(req, i->r) == 0){
115737da2899SCharles.Forsyth /*
115837da2899SCharles.Forsyth * if we'd sent a request and our requested rect has now changed,
115937da2899SCharles.Forsyth * then resend the request (via tkupdatewinsize),
116037da2899SCharles.Forsyth * otherwise accept the new size and repack if necessary
116137da2899SCharles.Forsyth */
116237da2899SCharles.Forsyth if(reqid != -1 && tkw->changed){
116337da2899SCharles.Forsyth if(tkupdatewinsize(tk))
116437da2899SCharles.Forsyth return "!requested size has changed";
116537da2899SCharles.Forsyth
116637da2899SCharles.Forsyth } else if(Dx(req) != Dx(i->r) || Dy(req) != Dy(i->r)){
116737da2899SCharles.Forsyth tk->flag |= Tksuspended;
116837da2899SCharles.Forsyth tk->act.width = Dx(i->r) - bw2;
116937da2899SCharles.Forsyth tk->act.height = Dy(i->r) - bw2;
117037da2899SCharles.Forsyth tk->req = tk->act;
117137da2899SCharles.Forsyth prop = tk->flag & Tknoprop;
117237da2899SCharles.Forsyth tk->flag |= Tknoprop;
117337da2899SCharles.Forsyth tkpackqit(tk);
117437da2899SCharles.Forsyth tkrunpack(top);
117537da2899SCharles.Forsyth tk->flag = (tk->flag & ~Tknoprop) | prop;
117637da2899SCharles.Forsyth resize = 1;
117737da2899SCharles.Forsyth }
117837da2899SCharles.Forsyth }
117937da2899SCharles.Forsyth if(reqid == -1)
118037da2899SCharles.Forsyth tkw->reqid++; /* invalidate all buffered requests. */
118137da2899SCharles.Forsyth tkw->act = i->r.min;
118237da2899SCharles.Forsyth tkw->req = tkw->act;
118337da2899SCharles.Forsyth tkw->changed = 0;
118437da2899SCharles.Forsyth tk->req.width = Dx(i->r) - bw2;
118537da2899SCharles.Forsyth tk->req.height = Dy(i->r) - bw2;
118637da2899SCharles.Forsyth tk->act = tk->req;
118737da2899SCharles.Forsyth if((tk->flag & Tkmapped) == 0){
118837da2899SCharles.Forsyth tk->flag |= Tkmapped;
118937da2899SCharles.Forsyth tkdeliver(tk, TkMap, nil);
119037da2899SCharles.Forsyth }
119137da2899SCharles.Forsyth if(tksetwindrawimage(tk, di) == 0 || resize){
119237da2899SCharles.Forsyth tk->dirty = tkrect(tk, 1);
119337da2899SCharles.Forsyth tk->flag |= Tkrefresh;
119437da2899SCharles.Forsyth }
119537da2899SCharles.Forsyth tk->flag &= ~Tksuspended;
119637da2899SCharles.Forsyth
119737da2899SCharles.Forsyth lookupimage(di); /* make sure limbo image coords correspond correctly */
119837da2899SCharles.Forsyth tkupdate(top);
119937da2899SCharles.Forsyth return nil;
120037da2899SCharles.Forsyth }
120137da2899SCharles.Forsyth
120237da2899SCharles.Forsyth void
tkwreq(TkTop * top,char * fmt,...)120337da2899SCharles.Forsyth tkwreq(TkTop *top, char *fmt, ...)
120437da2899SCharles.Forsyth {
120537da2899SCharles.Forsyth char *buf;
120637da2899SCharles.Forsyth va_list arg;
120737da2899SCharles.Forsyth
120837da2899SCharles.Forsyth va_start(arg, fmt);
120937da2899SCharles.Forsyth buf = vsmprint(fmt, arg);
121037da2899SCharles.Forsyth va_end(arg);
121137da2899SCharles.Forsyth tktolimbo(top->wreq, buf);
121237da2899SCharles.Forsyth free(buf);
121337da2899SCharles.Forsyth }
121437da2899SCharles.Forsyth
121537da2899SCharles.Forsyth int
tktolimbo(void * var,char * msg)121637da2899SCharles.Forsyth tktolimbo(void *var, char *msg)
121737da2899SCharles.Forsyth {
121837da2899SCharles.Forsyth void *ptrs[1];
121937da2899SCharles.Forsyth int r;
122037da2899SCharles.Forsyth
122137da2899SCharles.Forsyth if(var==H)
122237da2899SCharles.Forsyth return 0;
122337da2899SCharles.Forsyth ptrs[0] = H;
122437da2899SCharles.Forsyth retstr(msg, (String**) &ptrs[0]);
122537da2899SCharles.Forsyth r = csendalt((Channel *)var, ptrs, &Tptr, TkMaxmsgs);
122637da2899SCharles.Forsyth return r;
122737da2899SCharles.Forsyth }
122837da2899SCharles.Forsyth
122937da2899SCharles.Forsyth static void
hexify(char * buf,int n)123037da2899SCharles.Forsyth hexify(char *buf, int n)
123137da2899SCharles.Forsyth {
123237da2899SCharles.Forsyth static char hex[] = "0123456789abcdef";
123337da2899SCharles.Forsyth uchar b;
123437da2899SCharles.Forsyth char *dp, *fp;
123537da2899SCharles.Forsyth fp = buf+n;
123637da2899SCharles.Forsyth dp = buf+n*2;
123737da2899SCharles.Forsyth *dp-- = '\0';
123837da2899SCharles.Forsyth while(fp-- > buf){
123937da2899SCharles.Forsyth b = (uchar)*fp;
124037da2899SCharles.Forsyth *dp-- = hex[b & 0xf];
124137da2899SCharles.Forsyth *dp-- = hex[b >> 4];
124237da2899SCharles.Forsyth }
124337da2899SCharles.Forsyth }
124437da2899SCharles.Forsyth
124537da2899SCharles.Forsyth char*
tkcursorswitch(TkTop * top,Image * i,TkImg * img)124637da2899SCharles.Forsyth tkcursorswitch(TkTop *top, Image *i, TkImg *img)
124737da2899SCharles.Forsyth {
124837da2899SCharles.Forsyth Image *ci, *scratch;
124937da2899SCharles.Forsyth char *buf;
125037da2899SCharles.Forsyth Rectangle r;
125137da2899SCharles.Forsyth int n, maxb, nb;
125237da2899SCharles.Forsyth
125337da2899SCharles.Forsyth if(i == nil && img == nil){
125437da2899SCharles.Forsyth tktolimbo(top->wreq, "cursor");
125537da2899SCharles.Forsyth return nil;
125637da2899SCharles.Forsyth }
125737da2899SCharles.Forsyth
125837da2899SCharles.Forsyth if(img != nil){
125937da2899SCharles.Forsyth if(img->cursor){
126037da2899SCharles.Forsyth tktolimbo(top->wreq, img->cursor);
126137da2899SCharles.Forsyth return nil;
126237da2899SCharles.Forsyth }
126337da2899SCharles.Forsyth i = img->img;
126437da2899SCharles.Forsyth }
126537da2899SCharles.Forsyth if(i->depth != 1 || Dx(i->r)*Dy(i->r) > 16000 || Dy(i->r)%8 != 0 || Dy(i->r)%2 != 0)
126637da2899SCharles.Forsyth return TkBadcursor;
126737da2899SCharles.Forsyth /*
126837da2899SCharles.Forsyth * readjust image, inferring hotspot from origin.
126937da2899SCharles.Forsyth */
127037da2899SCharles.Forsyth if(i->r.min.x != 0 || i->r.min.y != 0){
127137da2899SCharles.Forsyth r.min.x = 0;
127237da2899SCharles.Forsyth r.min.y = 0;
127337da2899SCharles.Forsyth r.max.x = Dx(i->r);
127437da2899SCharles.Forsyth r.max.y = Dy(i->r);
127537da2899SCharles.Forsyth scratch = allocimage(i->display, r, GREY1, 0, DNofill);
127637da2899SCharles.Forsyth if(scratch == nil)
127737da2899SCharles.Forsyth return TkNomem;
127837da2899SCharles.Forsyth draw(scratch, r, i, nil, i->r.min);
127937da2899SCharles.Forsyth ci = scratch;
128037da2899SCharles.Forsyth }else{
128137da2899SCharles.Forsyth scratch = nil;
128237da2899SCharles.Forsyth ci = i;
128337da2899SCharles.Forsyth }
128437da2899SCharles.Forsyth nb = ci->r.max.x/8 * ci->r.max.y;
128537da2899SCharles.Forsyth maxb = 7 + 12*4 + 2*nb + 1;
128637da2899SCharles.Forsyth buf = mallocz(maxb, 0);
128737da2899SCharles.Forsyth if(buf == nil)
128837da2899SCharles.Forsyth return TkNomem;
128937da2899SCharles.Forsyth n = sprint(buf, "cursor %d %d %d %d ", i->r.min.x, i->r.min.y, ci->r.max.x, ci->r.max.y);
129037da2899SCharles.Forsyth unloadimage(ci, ci->r, (uchar*)buf+n, maxb-n);
129137da2899SCharles.Forsyth hexify(buf+n, nb);
129237da2899SCharles.Forsyth tktolimbo(top->wreq, buf);
129337da2899SCharles.Forsyth if(img != nil){
129437da2899SCharles.Forsyth free(img->cursor);
129537da2899SCharles.Forsyth img->cursor = buf;
129637da2899SCharles.Forsyth }
129737da2899SCharles.Forsyth freeimage(scratch);
129837da2899SCharles.Forsyth return nil;
129937da2899SCharles.Forsyth }
130037da2899SCharles.Forsyth
130137da2899SCharles.Forsyth void
tkcursorset(TkTop * t,Point p)130237da2899SCharles.Forsyth tkcursorset(TkTop *t, Point p)
130337da2899SCharles.Forsyth {
130437da2899SCharles.Forsyth tkwreq(t, "ptr %d %d", p.x, p.y);
130537da2899SCharles.Forsyth }
1306