void tkcvslinesize(TkCitem *i) { TkCline *l; int j, w, as, shape[3], arrow; l = TKobj(TkCline, i); w = TKF2I(l->width); i->p.bb = bbnil; tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb); l->arrowf = l->capstyle; l->arrowl = l->capstyle; if(l->arrow != 0) { as = w/3; if(as < 1) as = 1; for(j = 0; j < 3; j++) { shape[j] = l->shape[j]; if(shape[j] == 0) shape[j] = as * cvslshape[j]; } arrow = ARROW(TKF2I(shape[0]), TKF2I(shape[1]), TKF2I(shape[2])); if(l->arrow & TkCarrowf) l->arrowf = arrow; if(l->arrow & TkCarrowl) l->arrowl = arrow; w += shape[2]; } i->p.bb = insetrect(i->p.bb, -w); }
static char* tkscalecoords(Tk *tk, char *arg, char **val) { int p, x, y, l, value; TkScale *tks = TKobj(TkScale, tk); char *e; value = tks->value; if(arg != nil && arg[0] != '\0') { e = tkfracword(tk->env->top, &arg, &value, tk->env); if (e != nil) return e; } value -= tks->from; p = tks->pixmax - tks->pixmin; l = TKF2I(tks->to-tks->from); if (l==0) p /= 2; else p = TKF2I(value*p/l); p += tks->pixmin; if(tks->orient == Tkvertical) { x = tks->center; y = p; } else { x = p; y = tks->center; } return tkvalue(val, "%d %d", x, y); }
char* tkcvstextcoord(TkCitem *i, char *arg, int x, int y) { char *e; TkCpoints p; if(arg == nil) { tkxlatepts(i->p.parampt, i->p.npoint, x, y); tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y)); i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y))); } else { e = tkparsepts(i->env->top, &p, &arg, 0); if(e != nil) return e; if(p.npoint != 1) { tkfreepoint(&p); return TkFewpt; } tkfreepoint(&i->p); i->p = p; tkcvstextsize(i); } return nil; }
void tkcvsrectdraw(Image *img, TkCitem *i, TkEnv *pe) { int lw, rw; TkEnv *e; TkCrect *r; Rectangle d, rr; Point tr, bl; Image *pen; USED(pe); d.min = i->p.drawpt[0]; d.max = i->p.drawpt[1]; e = i->env; r = TKobj(TkCrect, i); pen = nil; if((e->set & (1<<TkCfill))) pen = tkgc(e, TkCfill); if(pen != nil) draw(img, d, pen, r->stipple, d.min); tr.x = d.max.x; tr.y = d.min.y; bl.x = d.min.x; bl.y = d.max.y; rw = (TKF2I(r->width) + 1)/2; if(rw <= 0) return; lw = (TKF2I(r->width))/2; pen = tkgc(e, TkCforegnd); if(pen != nil) { /* horizontal lines first */ rr.min.x = d.min.x - lw; rr.max.x = d.max.x + rw; rr.min.y = d.min.y - lw; rr.max.y = d.min.y + rw; draw(img, rr, pen, nil, rr.min); rr.min.y += Dy(d); rr.max.y += Dy(d); draw(img, rr, pen, nil, rr.min); /* now the vertical */ /* horizontal lines first */ rr.min.x = d.min.x - lw; rr.max.x = d.min.x + rw; rr.min.y = d.min.y + rw; rr.max.y = d.max.y - lw; draw(img, rr, pen, nil, rr.min); rr.min.x += Dx(d); rr.max.x += Dx(d); draw(img, rr, pen, nil, rr.min); } }
static char* tkcvsscale(Tk *tk, char *arg, char **val) { TkName *f; TkCtag *t; TkCanvas *c; TkCpoints pts; TkCitem *item; int j; char *e, buf[Tkmaxitem]; Point *p, *d, origin, scalef; USED(val); c = TKobj(TkCanvas, tk); arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); f = tkctaglook(tk, nil, buf); if(f == nil || f->obj == nil) return TkBadtg; e = tkparsepts(tk->env->top, &pts, &arg, 0); if(e != nil) return e; if(pts.npoint != 2) { tkfreepoint(&pts); return TkFewpt; } origin = pts.parampt[0]; scalef = pts.parampt[1]; tkfreepoint(&pts); for(t = f->obj; t; t = t->taglist) { item = t->item; p = item->p.parampt; d = item->p.drawpt; for(j = 0; j < item->p.npoint; j++) { p->x -= origin.x; p->y -= origin.y; p->x = TKF2I(p->x*scalef.x); p->y = TKF2I(p->y*scalef.y); p->x += origin.x; p->y += origin.y; d->x = TKF2I(p->x); d->y = TKF2I(p->y); d++; p++; } tkbbmax(&c->update, &item->p.bb); e = tkcimethod[item->type].coord(item, nil, 0, 0); tkbbmax(&c->update, &item->p.bb); if(e != nil) return e; tkcvssetdirty(tk); } return nil; }
static char* tkscaledrag(Tk *tk, char *arg, char **val) { int x, y, v; char *e, buf[Tkmaxitem], f[32]; TkScale *tks = TKobj(TkScale, tk); USED(val); if((tks->flag & Dragging) == 0) return nil; if(tks->flag & Autorepeat) return nil; e = tkfracword(tk->env->top, &arg, &x, tk->env); if(e != nil) return e; e = tkfracword(tk->env->top, &arg, &y, tk->env); if(e != nil) return e; if(tks->orient == Tkvertical) v = TKF2I(y) + tk->borderwidth; else v = TKF2I(x) + tk->borderwidth; v -= tks->pix; x = tks->pixmax-tks->pixmin; if (x!=tks->sl) v = tks->base + (vlong)v * (tks->to-tks->from)/(x-tks->sl); else v = tks->base; if(tks->res > 0) { int a = tks->res / 2; if (v < 0) a = -a; v = ((v+a)/tks->res)*tks->res; } tks->value = v; tkscalecheckvalue(tk); if(tks->command != nil && tks->jump != BoolT) { tkfprint(f, tks->value); snprint(buf, sizeof(buf), "%s %s", tks->command, f); e = tkexec(tk->env->top, buf, nil); } tk->dirty = tkrect(tk, 1); return e; }
void tkcvslinedraw(Image *img, TkCitem *i, TkEnv *pe) { int w; Point *p; TkCline *l; Image *pen; USED(pe); l = TKobj(TkCline, i); pen = l->pen; if(pen == nil) pen = tkgc(i->env, TkCforegnd); w = TKF2I(l->width)/2; if(w < 0) return; p = i->p.drawpt; if(l->smooth == BoolT && i->p.npoint >= 3) bezspline(img, p, i->p.npoint, l->arrowf, l->arrowl, w, pen, p[0]); else poly(img, p, i->p.npoint, l->arrowf, l->arrowl, w, pen, p[0]); }
char* tkscale(TkTop *t, char *arg, char **ret) { Tk *tk; char *e; TkName *names; TkScale *tks; TkOptab tko[3]; tk = tknewobj(t, TKscale, sizeof(Tk)+sizeof(TkScale)); if(tk == nil) return TkNomem; tk->flag |= Tktakefocus; tks = TKobj(TkScale, tk); tks->res = TKI2F(1); tks->to = TKI2F(100); tks->len = ScaleLen; tks->orient = Tkvertical; tks->relief = TKraised; tks->sl = ScaleSlider; tks->sv = BoolT; tks->bigi = 0; tko[0].ptr = tk; tko[0].optab = tkgeneric; tko[1].ptr = tks; tko[1].optab = opts; tko[2].ptr = nil; names = nil; e = tkparse(t, arg, tko, &names); if(e != nil) { tkfreeobj(tk); return e; } tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd)); tkscalecheckvalue(tk); tksizescale(tk); if (tks->bigi == 0) tks->bigi = TKI2F(TKF2I(tks->to - tks->from) / 10); e = tkbindings(t, tk, b, nelem(b)); if(e != nil) { tkfreeobj(tk); return e; } e = tkaddchild(t, tk, &names); tkfreename(names); if(e != nil) { tkfreeobj(tk); return e; } tk->name->link = nil; return tkvalue(ret, "%s", tk->name->name); }
static void tkhscroll(Tk *tk, TkScroll *tks, Image *i, Point size) { TkEnv *e; Point p[3], o; int bo, w, h, triangle; e = tk->env; triangle = tk->act.height - Elembw; bo = tk->borderwidth + Elembw; p[0].x = bo; p[0].y = size.y/2; p[1].x = p[0].x + triangle; p[1].y = p[0].y - triangle/2 + 1; p[2].x = p[0].x + triangle; p[2].y = p[0].y + triangle/2 - 2; drawarrow(tks, i, p, e, ActiveA1, ButtonA1); tks->a1 = p[2].x; w = p[2].x + Elembw; p[0].x = size.x - bo - 1; p[1].x = p[0].x - triangle; p[2].x = p[0].x - triangle; drawarrow(tks, i, p, e, ActiveA2, ButtonA2); tks->a2 = p[2].x; o.x = bo + triangle + 2*Elembw; o.y = tk->borderwidth; w = p[2].x - 2*Elembw - w - 2*tk->borderwidth; h = size.y - 2*bo; o.x += TKF2I(tks->top*w); w *= tks->bot - tks->top; w = TKF2I(w); tks->t1 = o.x - Elembw; tks->t2 = o.x + w + Elembw; drawslider(tks, i, o, w, h, e); }
static void tkvscroll(Tk *tk, TkScroll *tks, Image *i, Point size) { TkEnv *e; Point p[3], o; int bo, w, h, triangle; e = tk->env; triangle = tk->act.width - Elembw; bo = tk->borderwidth + Elembw; p[0].x = size.x/2; p[0].y = bo; p[1].x = p[0].x - triangle/2; p[1].y = p[0].y + triangle; p[2].x = p[0].x + triangle/2; p[2].y = p[0].y + triangle; drawarrow(tks, i, p, e, ActiveA1, ButtonA1); tks->a1 = p[2].y; h = p[2].y + Elembw; p[0].y = size.y - bo - 1; p[1].y = p[0].y - triangle; p[2].y = p[0].y - triangle; drawarrow(tks, i, p, e, ActiveA2, ButtonA2); tks->a2 = p[2].y; o.x = tk->borderwidth ; o.y = bo + triangle + 2*Elembw; w = size.x - 2*bo; h = p[2].y - 2*Elembw - h - 2*tk->borderwidth; o.y += TKF2I(tks->top*h); h *= tks->bot - tks->top; h = TKF2I(h); tks->t1 = o.y - Elembw; tks->t2 = o.y + h + Elembw; drawslider(tks, i, o, w, h, e); }
static char* tkcvsview(Tk *tk, char *arg, char **val, int nl, int *posn, int min, int max, int inc) { TkTop *t; int top, bot, diff, amount; char *e; char buf[Tkmaxitem], *v; diff = max-min; if(*arg == '\0') { if ( diff == 0 ) top = bot = 0; else { top = TKI2F(*posn-min)/diff; bot = TKI2F(*posn+nl-min)/diff; } v = tkfprint(buf, top); *v++ = ' '; tkfprint(v, bot); return tkvalue(val, "%s", buf); } t = tk->env->top; arg = tkword(t, arg, buf, buf+sizeof(buf), nil); if(strcmp(buf, "moveto") == 0) { e = tkfrac(&arg, &top, nil); if (e != nil) return e; *posn = min + TKF2I((top+1)*diff); } else if(strcmp(buf, "scroll") == 0) { arg = tkword(t, arg, buf, buf+sizeof(buf), nil); amount = atoi(buf); tkword(t, arg, buf, buf+sizeof(buf), nil); if(buf[0] == 'p') /* Pages */ amount = amount * nl * 9 /10; else if (inc > 0) amount *= inc; else amount = amount * nl / 10; *posn += amount; } else return TkBadcm; bot = max - nl; if(*posn > bot) *posn = bot; if(*posn < min) *posn = min; tk->dirty = tkrect(tk, 0); return nil; }
static char* tkcvsyview(Tk *tk, char *arg, char **val) { int si; char *e; TkCanvas *c = TKobj(TkCanvas, tk); si = TKF2I(c->yscrolli); e = tkcvsview(tk, arg, val, tk->act.height, &c->view.y, c->region.min.y, c->region.max.y, si); tkcvssv(tk); return e; }
static char* tkcvsxview(Tk *tk, char *arg, char **val) { int si; char *e; TkCanvas *c = TKobj(TkCanvas, tk); si = TKF2I(c->xscrolli); e = tkcvsview(tk, arg, val, tk->act.width, &c->view.x, c->region.min.x, c->region.max.x, si); tkcvssh(tk); return e; }
char* tkscaleposn(TkEnv *env, Tk *tk, char *arg, int *z) { int x, y; TkScale *tks = TKobj(TkScale, tk); char *e; e = tkfracword(env->top, &arg, &x, env); if(e != nil) return e; e = tkfracword(env->top, &arg, &y, env); if(e != nil) return e; x = TKF2I(x) + tk->borderwidth; y = TKF2I(y) + tk->borderwidth; if(tks->orient == Tkvertical) { if(z != nil) { z[0] = x; z[1] = y; } x = y; } else { if(z != nil) { z[0] = y; z[1] = x; } } if(x > tks->pixmin && x < tks->pixpos) return trough1; else if(x >= tks->pixpos && x < tks->pixpos+tks->sl+2*ScaleBW) return slider; else if(x >= tks->pixpos+tks->sl+2*ScaleBW && x < tks->pixmax) return trough2; return ""; }
char* tkcvswindcoord(TkCitem *i, char *arg, int x, int y) { char *e; TkCpoints p; /* TkCwind *w; int xi, yi; */ if(arg == nil) { tkxlatepts(i->p.parampt, i->p.npoint, x, y); tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y)); tkcvswindsize(i); /* w = TKobj(TkCwind, i); xi = TKF2I(x); yi = TKF2I(y); if (w->sub != nil) { w->sub->act.x += xi; w->sub->act.y += yi; } i->p.bb = rectaddpt(i->p.bb, Pt(xi, yi)); */ } else { e = tkparsepts(i->env->top, &p, &arg, 0); if(e != nil) return e; if(p.npoint != 1) { tkfreepoint(&p); return TkFewpt; } tkfreepoint(&i->p); i->p = p; tkcvswindsize(i); } return nil; }
void tkcvsrectsize(TkCitem *i) { TkCrect *r; int w; r = TKobj(TkCrect, i); w = TKF2I(r->width)*2; i->p.bb = bbnil; tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb); i->p.bb = insetrect(i->p.bb, -w); }
static char* tkscaleget(Tk *tk, char *arg, char **val) { int x, y, value, v, l; char buf[Tkminitem], *e; TkScale *tks = TKobj(TkScale, tk); value = tks->value; if(arg[0] != '\0') { e = tkfracword(tk->env->top, &arg, &x, tk->env); if (e != nil) return e; e = tkfracword(tk->env->top, &arg, &y, tk->env); if (e != nil) return e; if(tks->orient == Tkvertical) v = TKF2I(y) + tk->borderwidth; else v = TKF2I(x) + tk->borderwidth; if(v < tks->pixmin) value = tks->from; else if(v > tks->pixmax) value = tks->to; else { l = tks->pixmax-tks->pixmin; value = 0; if (l!=0) value = v * ((tks->to-tks->from)/l); value += tks->from; } if(tks->res > 0) value = (value/tks->res)*tks->res; } tkfprint(buf, value); return tkvalue(val, "%s", buf); }
static char* tkcvssee(Tk *tk, char *arg, char **val) { Rectangle r; int n, coords[4]; char *e; USED(val); n = 0; while (n < 4) { if (*arg == '\0') break; e = tkfracword(tk->env->top, &arg, &coords[n++], nil); if (e != nil) return e; } if (n != 2 && n != 4) return TkFewpt; r.min.x = TKF2I(coords[0]); r.min.y = TKF2I(coords[1]); if (n == 4) { r.max.x = TKF2I(coords[2]); r.max.y = TKF2I(coords[3]); } else r.max = r.min; r = canonrect(r); /* * XXX should intersect r with scrollregion here, as you shouldn't * be able to display things outside the scroll region. (??) */ tkcvsseerect(tk, r, r.min); return nil; }
int tkcvslinehit(TkCitem *i, Point p) { TkCline *l; int w, np, r; Point *pp; l = TKobj(TkCline, i); w =TKF2I(l->width) + 2; /* 2 for slop */ if (l->smooth == BoolT) { np = getbezsplinepts(i->p.drawpt, i->p.npoint, &pp); r = tklinehit(pp, np, w, p); free(pp); } else r = tklinehit(i->p.drawpt, i->p.npoint, w, p); return r; }
static void tkcvsf2i(Tk *tk, TkCanvas *tkc) { Rectangle r; tk->req.width = TKF2I(tkc->width); tk->req.height = TKF2I(tkc->height); r.min.x = TKF2I(tkc->scrollr[0]); r.min.y = TKF2I(tkc->scrollr[1]); r.max.x = TKF2I(tkc->scrollr[2]); r.max.y = TKF2I(tkc->scrollr[3]); /* * make sure that the region is big enough to hold * the actually displayed area */ if (Dx(r) < tk->act.width) r.max.x = r.min.x + tk->act.width; if (Dy(r) < tk->act.height) r.max.y = r.min.y + tk->act.height; tkc->region = r; /* * make sure that the view origin is at a valid * position with respect to the scroll region. */ if (tkc->view.x + tk->act.width > r.max.x) tkc->view.x = r.max.x - tk->act.width; if (tkc->view.x < r.min.x) tkc->view.x = r.min.x; if (tkc->view.y + tk->act.height > r.max.y) tkc->view.y = r.max.y - tk->act.height; if (tkc->view.y < r.min.y) tkc->view.y = r.min.y; }
static char* tkentryxview(Tk *tk, char *arg, char **val) { int locked; TkEnv *env; TkEntry *tke; char *buf, *v; int dx, top, bot, amount, ix, x; char *e; tke = TKobj(TkEntry, tk); env = tk->env; dx = tk->act.width - 2*xinset(tk); buf = mallocz(Tkmaxitem, 0); if(buf == nil) return TkNomem; if(*arg == '\0') { if (tke->textlen == 0 || tke->xlen < dx) { bot = TKI2F(0); top = TKI2F(1); } else { bot = TKI2F(tke->x0) / tke->xlen; top = TKI2F(tke->x0 + dx) / tke->xlen; } v = tkfprint(buf, bot); *v++ = ' '; tkfprint(v, top); e = tkvalue(val, "%s", buf); free(buf); return e; } arg = tkitem(buf, arg); if(strcmp(buf, "moveto") == 0) { e = tkfracword(env->top, &arg, &top, nil); if (e != nil) { free(buf); return e; } tke->x0 = TKF2I(top*tke->xlen); } else if(strcmp(buf, "scroll") == 0) { arg = tkitem(buf, arg); amount = atoi(buf); if(*arg == 'p') /* Pages */ amount *= (9*tke->xlen)/10; else if(*arg == 's') { /* Inferno-ism, "scr", must be used in the context of button2p */ x = amount; amount = x < tke->oldx ? env->wzero : (x > tke->oldx ? -env->wzero : 0); tke->oldx = x; } tke->x0 += amount; } else { e = tkentryparseindex(tk, buf, &ix); if(e != nil) { free(buf); return e; } locked = lockdisplay(env->top->display); tke->x0 = entrytextwidth(tk, ix); if (locked) unlockdisplay(env->top->display); } free(buf); if (tke->x0 > tke->xlen - dx) tke->x0 = tke->xlen - dx; if (tke->x0 < 0) tke->x0 = 0; recalcentry(tk); e = tkentrysh(tk); blinkreset(tk); tk->dirty = tkrect(tk, 1); return e; }
char* tkcvstags(Tk *tk, char *arg, char **val, int af) { TkTop *o; int x, y; TkName *f; TkCtag *t, *tt; char *fmt; TkCpoints p; TkCanvas *c; TkCitem *i, *b; int d, dist, dx, dy; char tag[Tkmaxitem], buf[Tkmaxitem]; char *e; USED(val); c = TKobj(TkCanvas, tk); o = tk->env->top; if(af == TkCadd) { arg = tkword(o, arg, tag, tag+sizeof(tag), nil); if(tag[0] == '\0' || (tag[0] >= '0' && tag[0] <= '9')) return TkBadtg; } fmt = "%d"; arg = tkword(o, arg, buf, buf+sizeof(buf), nil); if(strcmp(buf, "above") == 0) { tkword(o, arg, buf, buf+sizeof(buf), nil); f = tkctaglook(tk, nil, buf); if(f == nil) return TkBadtg; t = tkclasttag(c->head, f->obj); if(t == nil) return TkBadtg; for(i = t->item->next; i; i = i->next) { if(af == TkCadd) { i->tags = tkmkname(tag); if(i->tags == nil) return TkNomem; tkcaddtag(tk, i, 0); } else { e = tkvalue(val, fmt, i->id); if(e != nil) return e; fmt = " %d"; } } return nil; } if(strcmp(buf, "all") == 0) { for(i = c->head; i; i = i->next) { if(af == TkCadd) { i->tags = tkmkname(tag); if(i->tags == nil) return TkNomem; tkcaddtag(tk, i, 0); } else { e = tkvalue(val, fmt, i->id); if(e != nil) return e; fmt = " %d"; } } return nil; } if(strcmp(buf, "below") == 0) { tkword(o, arg, buf, buf+sizeof(buf), nil); f = tkctaglook(tk, nil, buf); if(f == nil) return TkBadtg; tt = f->obj; for(b = c->head; b; b = b->next) { for(t = tt; t; t = t->itemlist) if(t->item == b) goto found; } found: for(i = c->head; i != b; i = i->next) { if(af == TkCadd) { i->tags = tkmkname(tag); if(i->tags == nil) return TkNomem; tkcaddtag(tk, i, 0); } else { e = tkvalue(val, fmt, i->id); if(e != nil) return e; fmt = " %d"; } } return nil; } if(strcmp(buf, "closest") == 0) { e = tkfracword(o, &arg, &x, nil); if (e == nil) e = tkfracword(o, &arg, &y, nil); if (e != nil) return e; if(*arg != '\0') return "!not implemented"; x = TKF2I(x); y = TKF2I(y); i = nil; dist = 0; for(b = c->head; b != nil; b = b->next) { dx = x - (b->p.bb.min.x + Dx(b->p.bb)/2); dy = y - (b->p.bb.min.y + Dy(b->p.bb)/2); d = dx*dx + dy*dy; if(d < dist || dist == 0) { i = b; dist = d; } } if(i == nil) return nil; if(af == TkCadd) { i->tags = tkmkname(tag); if(i->tags == nil) e = TkNomem; else tkcaddtag(tk, i, 0); } else e = tkvalue(val, fmt, i->id); return e; } if(strcmp(buf, "withtag") == 0) { tkword(o, arg, buf, buf+sizeof(buf), nil); f = tkctaglook(tk, nil, buf); if(f == nil) return TkBadtg; for(t = f->obj; t; t = t->taglist) { i = t->item; if(af == TkCadd) { i->tags = tkmkname(tag); if(i->tags == nil) return TkNomem; tkcaddtag(tk, i, 0); } else { e = tkvalue(val, fmt, i->id); if(e != nil) return e; fmt = " %d"; } } return nil; } if(strcmp(buf, "enclosed") == 0) { e = tkparsepts(o, &p, &arg, 0); if(e != nil) goto done; if(p.npoint != 2) { e = TkFewpt; goto done; } for(i = c->head; i; i = i->next) { if(rectinrect(i->p.bb, p.bb)) { if(af == TkCadd) { i->tags = tkmkname(tag); if(i->tags == nil) { e = TkNomem; goto done; } tkcaddtag(tk, i, 0); } else { e = tkvalue(val, fmt, i->id); if(e != nil) goto done; fmt = " %d"; } } } goto done; } if(strcmp(buf, "overlapping") == 0) { e = tkparsepts(o, &p, &arg, 0); if(e != nil) goto done; if(p.npoint != 2) { e = TkFewpt; goto done; } for(i = c->head; i; i = i->next) { if(rectXrect(i->p.bb, p.bb)) { if(af == TkCadd) { i->tags = tkmkname(tag); if(i->tags == nil) { e = TkNomem; goto done; } tkcaddtag(tk, i, 0); } else { e = tkvalue(val, "%d ", i->id); if(e != nil) goto done; } } } goto done; } return TkBadcm; done: /* both no error and error do the same thing */ tkfreepoint(&p); return e; }