123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693 |
- #include "lib9.h"
- #include "draw.h"
- #include "tk.h"
- #include "canvs.h"
- #include "textw.h"
- #include "kernel.h"
- TkCtxt*
- tknewctxt(Display *d)
- {
- TkCtxt *c;
- c = malloc(sizeof(TkCtxt));
- if(c == nil)
- return nil;
- c->lock = libqlalloc();
- if(c->lock == nil){
- free(c);
- return nil;
- }
- if (tkextnnewctxt(c) != 0) {
- free(c->lock);
- free(c);
- return nil;
- }
- c->display = d;
- return c;
- }
- void
- tkfreectxt(TkCtxt *c)
- {
- int locked;
- Display *d;
- if(c == nil)
- return;
- tkextnfreectxt(c);
- d = c->display;
- locked = lockdisplay(d);
- tkfreecolcache(c);
- freeimage(c->i);
- freeimage(c->ia);
- if(locked)
- unlockdisplay(d);
- libqlfree(c->lock);
- free(c);
- }
- Image*
- tkitmp(TkEnv *e, Point p, int fillcol)
- {
- Image *i, **ip;
- TkTop *t;
- TkCtxt *ti;
- Display *d;
- Rectangle r;
- ulong pix;
- int alpha;
-
- t = e->top;
- ti = t->ctxt;
- d = t->display;
- pix = e->colors[fillcol];
- alpha = (pix & 0xff) != 0xff;
- ip = alpha ? &ti->ia : &ti->i;
- if(*ip != nil) {
- i = *ip;
- if(p.x <= i->r.max.x && p.y <= i->r.max.y) {
- r.min = ZP;
- r.max = p;
- if (alpha)
- drawop(i, r, nil, nil, ZP, Clear);
- draw(i, r, tkgc(e, fillcol), nil, ZP);
- return i;
- }
- r = i->r;
- freeimage(i);
- if(p.x < r.max.x)
- p.x = r.max.x;
- if(p.y < r.max.y)
- p.y = r.max.y;
- }
- r.min = ZP;
- r.max = p;
- *ip = allocimage(d, r, alpha?RGBA32:d->image->chan, 0, pix);
- return *ip;
- }
- void
- tkgeomchg(Tk *tk, TkGeom *g, int bd)
- {
- int w, h;
- void (*geomfn)(Tk*);
- if(memcmp(&tk->req, g, sizeof(TkGeom)) == 0 && bd == tk->borderwidth)
- return;
- geomfn = tkmethod[tk->type]->geom;
- if(geomfn != nil)
- geomfn(tk);
- if(tk->master != nil) {
- tkpackqit(tk->master);
- tkrunpack(tk->env->top);
- }
- else
- if(tk->geom != nil) {
- w = tk->req.width;
- h = tk->req.height;
- tk->req.width = 0;
- tk->req.height = 0;
- tk->geom(tk, tk->act.x, tk->act.y, w, h);
- if (tk->slave) {
- tkpackqit(tk);
- tkrunpack(tk->env->top);
- }
- }
- tkdeliver(tk, TkConfigure, g);
- }
- /*
- * return the widget within tk with by point p (in widget coords)
- */
- Tk*
- tkinwindow(Tk *tk, Point p, int descend)
- {
- Tk *f;
- Point q;
- if (ptinrect(p, tkrect(tk, 1)) == 0)
- return nil;
- for (;;) {
- if (descend && tkmethod[tk->type]->inwindow != nil)
- f = tkmethod[tk->type]->inwindow(tk, &p);
- else {
- q = p;
- for (f = tk->slave; f; f = f->next) {
- q.x = p.x - (f->act.x + f->borderwidth);
- q.y = p.y - (f->act.y + f->borderwidth);
- if (ptinrect(q, tkrect(f, 1)))
- break;
- }
- p = q;
- }
- if (f == nil || f == tk)
- return tk;
- tk = f;
- }
- }
- Tk*
- tkfindfocus(TkTop *t, int x, int y, int descend)
- {
- Point p, q;
- Tk *tk, *f;
- TkWin *tkw;
- p.x = x;
- p.y = y;
- for(f = t->windows; f != nil; f = TKobj(TkWin, f)->next) {
- assert(f->flag&Tkwindow);
- if(f->flag & Tkmapped) {
- tkw = TKobj(TkWin, f);
- q.x = p.x - (tkw->act.x+f->borderwidth);
- q.y = p.y - (tkw->act.y+f->borderwidth);
- tk = tkinwindow(f, q, descend);
- if(tk != nil)
- return tk;
- }
- }
- return nil;
- }
- void
- tkmovewin(Tk *tk, Point p)
- {
- TkWin *tkw;
- if((tk->flag & Tkwindow) == 0)
- return;
- tkw = TKobj(TkWin, tk);
- if(! eqpt(p, tkw->req)){
- tkw->req = p;
- tkw->changed = 1;
- }
- }
- void
- tkmoveresize(Tk *tk, int x, int y, int w, int h)
- {
- TkWin *tkw;
- USED(x);
- USED(y);
- assert(tk->flag&Tkwindow);
- tkw = TKobj(TkWin, tk);
- if(w < 0)
- w = 0;
- if(h < 0)
- h = 0;
- //print("moveresize %s %d %d +[%d %d], callerpc %lux\n", tk->name->name, x, y, w, h, getcallerpc(&tk));
- tk->req.width = w;
- tk->req.height = h;
- tk->act = tk->req;
- /* XXX perhaps should actually suspend the window here? */
- tkw->changed = 1;
- }
- static void
- tkexterncreatewin(Tk *tk, Rectangle r)
- {
- TkWin *tkw;
- TkTop *top;
- char *name;
- top = tk->env->top;
- tkw = TKobj(TkWin, tk);
- /*
- * for a choicebutton menu, use the name of the choicebutton which created it
- */
- if(tk->name == nil){
- name = tkw->cbname;
- assert(name != nil);
- } else
- name = tk->name->name;
- tkw->reqid++;
- tkwreq(top, "!reshape %s %d %d %d %d %d", name, tkw->reqid, r.min.x, r.min.y, r.max.x, r.max.y);
- tkw->changed = 0;
- tk->flag |= Tksuspended;
- }
- /*
- * 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;
- }
- static char*
- tkdrawslaves1(Tk *tk, Point orig, Image *dst, int *dirty)
- {
- Tk *f;
- char *e = nil;
- Point worig;
- Rectangle r, oclip;
- worig.x = orig.x + tk->act.x + tk->borderwidth;
- worig.y = orig.y + tk->act.y + tk->borderwidth;
- r = rectaddpt(tk->dirty, worig);
- if (Dx(r) > 0 && rectXrect(r, dst->clipr)) {
- e = tkmethod[tk->type]->draw(tk, orig);
- tk->dirty = bbnil;
- *dirty = 1;
- }
- if(e != nil)
- return e;
- /*
- * grids need clipping
- * XXX BUG: they can't, 'cos text widgets don't clip appropriately.
- */
- if (tk->grid != nil) {
- r = rectaddpt(tkrect(tk, 0), worig);
- if (rectclip(&r, dst->clipr) == 0)
- return nil;
- oclip = dst->clipr;
- replclipr(dst, 0, r);
- }
- for(f = tk->slave; e == nil && f; f = f->next)
- e = tkdrawslaves1(f, worig, dst, dirty);
- if (tk->grid != nil)
- replclipr(dst, 0, oclip);
- return e;
- }
-
- char*
- tkdrawslaves(Tk *tk, Point orig, int *dirty)
- {
- Image *i;
- char *e;
- i = tkimageof(tk);
- if (i == nil)
- return nil;
- e = tkdrawslaves1(tk, orig, i, dirty);
- return e;
- }
- char*
- tkupdate(TkTop *t)
- {
- Tk* tk;
- int locked;
- TkWin *tkw;
- Display *d;
- char *e;
- int dirty = 0;
- if(t->noupdate)
- return nil;
- d = t->display;
- locked = lockdisplay(d);
- tk = t->windows;
- while(tk) {
- tkw = TKobj(TkWin, tk);
- if((tk->flag & (Tkmapped|Tksuspended)) == Tkmapped) {
- if (tkupdatewinsize(tk) == 0){
- e = tkdrawslaves(tk, ZP, &dirty);
- if(e != nil)
- return e;
- }
- }
- tk = tkw->next;
- }
- if (dirty || t->dirty) {
- flushimage(d, 1);
- t->dirty = 0;
- }
- if(locked)
- unlockdisplay(d);
- return nil;
- }
- int
- tkischild(Tk *tk, Tk *child)
- {
- while(child != nil && child != tk){
- if(child->master)
- child = child->master;
- else
- child = child->parent;
- }
- return child == tk;
- }
- void
- tksetbits(Tk *tk, int mask)
- {
- tk->flag |= mask;
- for(tk = tk->slave; tk; tk = tk->next)
- tksetbits(tk, mask);
- }
- char*
- tkmap(Tk *tk)
- {
- /*
- is this necessary?
- tkw = TKobj(TkWin, tk);
- if(tkw->image != nil)
- tkwreq(tk->env->top, "raise %s", tk->name->name);
- */
- if(tk->flag & Tkmapped)
- return nil;
- tk->flag |= Tkmapped;
- tkmoveresize(tk, 0, 0, tk->act.width, tk->act.height);
- tkdeliver(tk, TkMap, nil);
- return nil;
- //tkupdate(tk->env->top);
- }
- void
- tkunmap(Tk *tk)
- {
- TkTop *t;
- TkCtxt *c;
- while(tk->master)
- tk = tk->master;
- if((tk->flag & Tkmapped) == 0)
- return;
- t = tk->env->top;
- c = t->ctxt;
- if(tkischild(tk, c->mgrab))
- tksetmgrab(t, nil);
- if(tkischild(tk, c->entered)){
- tkdeliver(c->entered, TkLeave, nil);
- c->entered = nil;
- }
- if(tk == t->root)
- tksetglobalfocus(t, 0);
- tk->flag &= ~(Tkmapped|Tksuspended);
- tkdestroywinimage(tk);
- tkdeliver(tk, TkUnmap, nil);
- tkenterleave(t);
- /* XXX should unmap menus too */
- }
- Image*
- tkimageof(Tk *tk)
- {
- while(tk) {
- if(tk->flag & Tkwindow)
- return TKobj(TkWin, tk)->image;
- if(tk->parent != nil) {
- tk = tk->parent;
- switch(tk->type) {
- case TKmenu:
- return TKobj(TkWin, tk)->image;
- case TKcanvas:
- return TKobj(TkCanvas, tk)->image;
- case TKtext:
- return TKobj(TkText, tk)->image;
- }
- abort();
- }
- tk = tk->master;
- }
- return nil;
- }
- void
- tktopopt(Tk *tk, char *opt)
- {
- TkTop *t;
- TkWin *tkw;
- TkOptab tko[4];
- tkw = TKobj(TkWin, tk);
- t = tk->env->top;
- tko[0].ptr = tkw;
- tko[0].optab = tktop;
- tko[1].ptr = tk;
- tko[1].optab = tkgeneric;
- tko[2].ptr = t;
- tko[2].optab = tktopdbg;
- tko[3].ptr = nil;
- tkparse(t, opt, tko, nil);
- }
- /* general compare - compare top-left corners, y takes priority */
- static int
- tkfcmpgen(void *ap, void *bp)
- {
- TkWinfo *a = ap, *b = bp;
- if (a->r.min.y > b->r.min.y)
- return 1;
- if (a->r.min.y < b->r.min.y)
- return -1;
- if (a->r.min.x > b->r.min.x)
- return 1;
- if (a->r.min.x < b->r.min.x)
- return -1;
- return 0;
- }
- /* compare x-coords only */
- static int
- tkfcmpx(void *ap, void *bp)
- {
- TkWinfo *a = ap, *b = bp;
- return a->r.min.x - b->r.min.x;
- }
- /* compare y-coords only */
- static int
- tkfcmpy(void *ap, void *bp)
- {
- TkWinfo *a = ap, *b = bp;
- return a->r.min.y - b->r.min.y;
- }
- static void
- tkfintervalintersect(int min1, int max1, int min2, int max2, int *min, int *max)
- {
- if (min1 < min2)
- min1 = min2;
- if (max1 > max2)
- max1 = max2;
- if (max1 > min1) {
- *min = min1;
- *max = max1;
- } else
- *max = *min; /* no intersection */
- }
- void
- tksortfocusorder(TkWinfo *inf, int n)
- {
- int i;
- Rectangle overlap, r;
- int (*cmpfn)(void*, void*);
- overlap = inf[0].r;
- for (i = 0; i < n; i++) {
- r = inf[i].r;
- tkfintervalintersect(overlap.min.x, overlap.max.x,
- r.min.x, r.max.x, &overlap.min.x, &overlap.max.x);
- tkfintervalintersect(overlap.min.y, overlap.max.y,
- r.min.y, r.max.y, &overlap.min.y, &overlap.max.y);
- }
- if (Dx(overlap) > 0)
- cmpfn = tkfcmpy;
- else if (Dy(overlap) > 0)
- cmpfn = tkfcmpx;
- else
- cmpfn = tkfcmpgen;
- qsort(inf, n, sizeof(*inf), cmpfn);
- }
- void
- tkappendfocusorder(Tk *tk)
- {
- TkTop *tkt;
- tkt = tk->env->top;
- if (tk->flag & Tktakefocus)
- tkt->focusorder[tkt->nfocus++] = tk;
- if (tkmethod[tk->type]->focusorder != nil)
- tkmethod[tk->type]->focusorder(tk);
- }
- void
- tkbuildfocusorder(TkTop *tkt)
- {
- Tk *tk;
- int n;
- if (tkt->focusorder != nil)
- free(tkt->focusorder);
- n = 0;
- for (tk = tkt->root; tk != nil; tk = tk->siblings)
- if (tk->flag & Tktakefocus)
- n++;
- if (n == 0) {
- tkt->focusorder = nil;
- return;
- }
- tkt->focusorder = malloc(sizeof(*tkt->focusorder) * n);
- tkt->nfocus = 0;
- if (tkt->focusorder == nil)
- return;
- tkappendfocusorder(tkt->root);
- }
- void
- tkdirtyfocusorder(TkTop *tkt)
- {
- free(tkt->focusorder);
- tkt->focusorder = nil;
- tkt->nfocus = 0;
- }
- #define O(t, e) ((long)(&((t*)0)->e))
- #define OA(t, e) ((long)(((t*)0)->e))
- typedef struct TkSee TkSee;
- struct TkSee {
- int r[4];
- int p[2];
- int query;
- };
- static
- TkOption seeopts[] = {
- "rectangle", OPTfrac, OA(TkSee, r), IAUX(4),
- "point", OPTfrac, OA(TkSee, p), IAUX(2),
- "where", OPTbool, O(TkSee, query), nil,
- nil
- };
- 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;
- }
- /*
- * make rectangle r in widget tk visible if possible;
- * if not possible, at least make point p visible.
- */
- void
- tksee(Tk *tk, Rectangle r, Point p)
- {
- Point g;
- //print("tksee %R, %P in %s\n", r, p, tk->name->name);
- g = Pt(tk->borderwidth, tk->borderwidth);
- if(tk->parent != nil) {
- g = addpt(g, tkmethod[tk->parent->type]->relpos(tk));
- tk = tk->parent;
- } else {
- g.x += tk->act.x;
- g.y += tk->act.y;
- tk = tk->master;
- }
- r = rectaddpt(r, g);
- p = addpt(p, g);
- while (tk != nil) {
- if (tkmethod[tk->type]->see != nil){
- //print("see r %R, p %P in %s\n", r, p, tk->name->name);
- tkmethod[tk->type]->see(tk, &r, &p);
- //print("now r %R, p %P\n", r, p);
- }
- g = Pt(tk->borderwidth, tk->borderwidth);
- if (tk->parent != nil) {
- g = addpt(g, tkmethod[tk->parent->type]->relpos(tk));
- tk = tk->parent;
- } else {
- g.x += tk->act.x;
- g.y += tk->act.y;
- tk = tk->master;
- }
- r = rectaddpt(r, g);
- p = addpt(p, g);
- }
- }
|