1 #include "lib9.h" 2 #include "draw.h" 3 #include "tk.h" 4 #include "canvs.h" 5 #include "textw.h" 6 #include "kernel.h" 7 8 TkCtxt* 9 tknewctxt(Display *d) 10 { 11 TkCtxt *c; 12 c = malloc(sizeof(TkCtxt)); 13 if(c == nil) 14 return nil; 15 c->lock = libqlalloc(); 16 if(c->lock == nil){ 17 free(c); 18 return nil; 19 } 20 if (tkextnnewctxt(c) != 0) { 21 free(c->lock); 22 free(c); 23 return nil; 24 } 25 c->display = d; 26 return c; 27 } 28 29 void 30 tkfreectxt(TkCtxt *c) 31 { 32 int locked; 33 Display *d; 34 35 if(c == nil) 36 return; 37 38 tkextnfreectxt(c); 39 40 d = c->display; 41 locked = lockdisplay(d); 42 tkfreecolcache(c); 43 freeimage(c->i); 44 freeimage(c->ia); 45 if(locked) 46 unlockdisplay(d); 47 libqlfree(c->lock); 48 free(c); 49 } 50 51 Image* 52 tkitmp(TkEnv *e, Point p, int fillcol) 53 { 54 Image *i, **ip; 55 TkTop *t; 56 TkCtxt *ti; 57 Display *d; 58 Rectangle r; 59 ulong pix; 60 int alpha; 61 62 t = e->top; 63 ti = t->ctxt; 64 d = t->display; 65 66 pix = e->colors[fillcol]; 67 alpha = (pix & 0xff) != 0xff; 68 ip = alpha ? &ti->ia : &ti->i; 69 70 if(*ip != nil) { 71 i = *ip; 72 if(p.x <= i->r.max.x && p.y <= i->r.max.y) { 73 r.min = ZP; 74 r.max = p; 75 if (alpha) 76 drawop(i, r, nil, nil, ZP, Clear); 77 draw(i, r, tkgc(e, fillcol), nil, ZP); 78 return i; 79 } 80 r = i->r; 81 freeimage(i); 82 if(p.x < r.max.x) 83 p.x = r.max.x; 84 if(p.y < r.max.y) 85 p.y = r.max.y; 86 } 87 88 r.min = ZP; 89 r.max = p; 90 *ip = allocimage(d, r, alpha?RGBA32:d->image->chan, 0, pix); 91 92 return *ip; 93 } 94 95 void 96 tkgeomchg(Tk *tk, TkGeom *g, int bd) 97 { 98 int w, h; 99 void (*geomfn)(Tk*); 100 if(memcmp(&tk->req, g, sizeof(TkGeom)) == 0 && bd == tk->borderwidth) 101 return; 102 103 geomfn = tkmethod[tk->type]->geom; 104 if(geomfn != nil) 105 geomfn(tk); 106 107 if(tk->master != nil) { 108 tkpackqit(tk->master); 109 tkrunpack(tk->env->top); 110 } 111 else 112 if(tk->geom != nil) { 113 w = tk->req.width; 114 h = tk->req.height; 115 tk->req.width = 0; 116 tk->req.height = 0; 117 tk->geom(tk, tk->act.x, tk->act.y, w, h); 118 if (tk->slave) { 119 tkpackqit(tk); 120 tkrunpack(tk->env->top); 121 } 122 } 123 tkdeliver(tk, TkConfigure, g); 124 } 125 126 /* 127 * return the widget within tk with by point p (in widget coords) 128 */ 129 Tk* 130 tkinwindow(Tk *tk, Point p, int descend) 131 { 132 Tk *f; 133 Point q; 134 if (ptinrect(p, tkrect(tk, 1)) == 0) 135 return nil; 136 for (;;) { 137 if (descend && tkmethod[tk->type]->inwindow != nil) 138 f = tkmethod[tk->type]->inwindow(tk, &p); 139 else { 140 q = p; 141 for (f = tk->slave; f; f = f->next) { 142 q.x = p.x - (f->act.x + f->borderwidth); 143 q.y = p.y - (f->act.y + f->borderwidth); 144 if (ptinrect(q, tkrect(f, 1))) 145 break; 146 } 147 p = q; 148 } 149 if (f == nil || f == tk) 150 return tk; 151 tk = f; 152 } 153 } 154 155 Tk* 156 tkfindfocus(TkTop *t, int x, int y, int descend) 157 { 158 Point p, q; 159 Tk *tk, *f; 160 TkWin *tkw; 161 p.x = x; 162 p.y = y; 163 for(f = t->windows; f != nil; f = TKobj(TkWin, f)->next) { 164 assert(f->flag&Tkwindow); 165 if(f->flag & Tkmapped) { 166 tkw = TKobj(TkWin, f); 167 q.x = p.x - (tkw->act.x+f->borderwidth); 168 q.y = p.y - (tkw->act.y+f->borderwidth); 169 tk = tkinwindow(f, q, descend); 170 if(tk != nil) 171 return tk; 172 } 173 } 174 return nil; 175 } 176 177 void 178 tkmovewin(Tk *tk, Point p) 179 { 180 TkWin *tkw; 181 if((tk->flag & Tkwindow) == 0) 182 return; 183 tkw = TKobj(TkWin, tk); 184 if(! eqpt(p, tkw->req)){ 185 tkw->req = p; 186 tkw->changed = 1; 187 } 188 } 189 190 void 191 tkmoveresize(Tk *tk, int x, int y, int w, int h) 192 { 193 TkWin *tkw; 194 USED(x); 195 USED(y); 196 assert(tk->flag&Tkwindow); 197 tkw = TKobj(TkWin, tk); 198 if(w < 0) 199 w = 0; 200 if(h < 0) 201 h = 0; 202 //print("moveresize %s %d %d +[%d %d], callerpc %lux\n", tk->name->name, x, y, w, h, getcallerpc(&tk)); 203 tk->req.width = w; 204 tk->req.height = h; 205 tk->act = tk->req; 206 /* XXX perhaps should actually suspend the window here? */ 207 tkw->changed = 1; 208 } 209 210 static void 211 tkexterncreatewin(Tk *tk, Rectangle r) 212 { 213 TkWin *tkw; 214 TkTop *top; 215 char *name; 216 217 top = tk->env->top; 218 tkw = TKobj(TkWin, tk); 219 220 /* 221 * for a choicebutton menu, use the name of the choicebutton which created it 222 */ 223 if(tk->name == nil){ 224 name = tkw->cbname; 225 assert(name != nil); 226 } else 227 name = tk->name->name; 228 229 tkw->reqid++; 230 tkwreq(top, "!reshape %s %d %d %d %d %d", name, tkw->reqid, r.min.x, r.min.y, r.max.x, r.max.y); 231 tkw->changed = 0; 232 tk->flag |= Tksuspended; 233 } 234 235 /* 236 * return non-zero if the window size has changed (XXX choose better return value/function name!) 237 */ 238 int 239 tkupdatewinsize(Tk *tk) 240 { 241 TkWin *tkw; 242 Image *previ; 243 Rectangle r, or; 244 int bw2; 245 246 tkw = TKobj(TkWin, tk); 247 bw2 = 2*tk->borderwidth; 248 r.min.x = tkw->req.x; 249 r.min.y = tkw->req.y; 250 r.max.x = r.min.x + tk->act.width + bw2; 251 r.max.y = r.min.y + tk->act.height + bw2; 252 previ = tkw->image; 253 if(previ != nil){ 254 or.min.x = tkw->act.x; 255 or.min.y = tkw->act.y; 256 or.max.x = tkw->act.x + Dx(previ->r); 257 or.max.y = tkw->act.y + Dy(previ->r); 258 if(eqrect(or, r)) 259 return 0; 260 } 261 tkexterncreatewin(tk, r); 262 return 1; 263 } 264 265 static char* 266 tkdrawslaves1(Tk *tk, Point orig, Image *dst, int *dirty) 267 { 268 Tk *f; 269 char *e = nil; 270 Point worig; 271 Rectangle r, oclip; 272 273 worig.x = orig.x + tk->act.x + tk->borderwidth; 274 worig.y = orig.y + tk->act.y + tk->borderwidth; 275 276 r = rectaddpt(tk->dirty, worig); 277 if (Dx(r) > 0 && rectXrect(r, dst->clipr)) { 278 e = tkmethod[tk->type]->draw(tk, orig); 279 tk->dirty = bbnil; 280 *dirty = 1; 281 } 282 if(e != nil) 283 return e; 284 285 /* 286 * grids need clipping 287 * XXX BUG: they can't, 'cos text widgets don't clip appropriately. 288 */ 289 if (tk->grid != nil) { 290 r = rectaddpt(tkrect(tk, 0), worig); 291 if (rectclip(&r, dst->clipr) == 0) 292 return nil; 293 oclip = dst->clipr; 294 replclipr(dst, 0, r); 295 } 296 for(f = tk->slave; e == nil && f; f = f->next) 297 e = tkdrawslaves1(f, worig, dst, dirty); 298 if (tk->grid != nil) 299 replclipr(dst, 0, oclip); 300 return e; 301 } 302 303 char* 304 tkdrawslaves(Tk *tk, Point orig, int *dirty) 305 { 306 Image *i; 307 char *e; 308 i = tkimageof(tk); 309 if (i == nil) 310 return nil; 311 e = tkdrawslaves1(tk, orig, i, dirty); 312 return e; 313 } 314 315 char* 316 tkupdate(TkTop *t) 317 { 318 Tk* tk; 319 int locked; 320 TkWin *tkw; 321 Display *d; 322 char *e; 323 int dirty = 0; 324 if(t->noupdate) 325 return nil; 326 327 d = t->display; 328 locked = lockdisplay(d); 329 tk = t->windows; 330 while(tk) { 331 tkw = TKobj(TkWin, tk); 332 if((tk->flag & (Tkmapped|Tksuspended)) == Tkmapped) { 333 if (tkupdatewinsize(tk) == 0){ 334 e = tkdrawslaves(tk, ZP, &dirty); 335 if(e != nil) 336 return e; 337 } 338 } 339 tk = tkw->next; 340 } 341 if (dirty || t->dirty) { 342 flushimage(d, 1); 343 t->dirty = 0; 344 } 345 if(locked) 346 unlockdisplay(d); 347 return nil; 348 } 349 350 int 351 tkischild(Tk *tk, Tk *child) 352 { 353 while(child != nil && child != tk){ 354 if(child->master) 355 child = child->master; 356 else 357 child = child->parent; 358 } 359 return child == tk; 360 } 361 362 void 363 tksetbits(Tk *tk, int mask) 364 { 365 tk->flag |= mask; 366 for(tk = tk->slave; tk; tk = tk->next) 367 tksetbits(tk, mask); 368 } 369 370 char* 371 tkmap(Tk *tk) 372 { 373 /* 374 is this necessary? 375 tkw = TKobj(TkWin, tk); 376 if(tkw->image != nil) 377 tkwreq(tk->env->top, "raise %s", tk->name->name); 378 */ 379 380 if(tk->flag & Tkmapped) 381 return nil; 382 383 tk->flag |= Tkmapped; 384 tkmoveresize(tk, 0, 0, tk->act.width, tk->act.height); 385 tkdeliver(tk, TkMap, nil); 386 return nil; 387 //tkupdate(tk->env->top); 388 } 389 390 void 391 tkunmap(Tk *tk) 392 { 393 TkTop *t; 394 TkCtxt *c; 395 396 while(tk->master) 397 tk = tk->master; 398 399 if((tk->flag & Tkmapped) == 0) 400 return; 401 402 t = tk->env->top; 403 c = t->ctxt; 404 405 if(tkischild(tk, c->mgrab)) 406 tksetmgrab(t, nil); 407 if(tkischild(tk, c->entered)){ 408 tkdeliver(c->entered, TkLeave, nil); 409 c->entered = nil; 410 } 411 if(tk == t->root) 412 tksetglobalfocus(t, 0); 413 414 tk->flag &= ~(Tkmapped|Tksuspended); 415 416 tkdestroywinimage(tk); 417 tkdeliver(tk, TkUnmap, nil); 418 tkenterleave(t); 419 /* XXX should unmap menus too */ 420 } 421 422 Image* 423 tkimageof(Tk *tk) 424 { 425 while(tk) { 426 if(tk->flag & Tkwindow) 427 return TKobj(TkWin, tk)->image; 428 if(tk->parent != nil) { 429 tk = tk->parent; 430 switch(tk->type) { 431 case TKmenu: 432 return TKobj(TkWin, tk)->image; 433 case TKcanvas: 434 return TKobj(TkCanvas, tk)->image; 435 case TKtext: 436 return TKobj(TkText, tk)->image; 437 } 438 abort(); 439 } 440 tk = tk->master; 441 } 442 return nil; 443 } 444 445 void 446 tktopopt(Tk *tk, char *opt) 447 { 448 TkTop *t; 449 TkWin *tkw; 450 TkOptab tko[4]; 451 452 tkw = TKobj(TkWin, tk); 453 454 t = tk->env->top; 455 456 tko[0].ptr = tkw; 457 tko[0].optab = tktop; 458 tko[1].ptr = tk; 459 tko[1].optab = tkgeneric; 460 tko[2].ptr = t; 461 tko[2].optab = tktopdbg; 462 tko[3].ptr = nil; 463 464 tkparse(t, opt, tko, nil); 465 } 466 467 /* general compare - compare top-left corners, y takes priority */ 468 static int 469 tkfcmpgen(void *ap, void *bp) 470 { 471 TkWinfo *a = ap, *b = bp; 472 473 if (a->r.min.y > b->r.min.y) 474 return 1; 475 if (a->r.min.y < b->r.min.y) 476 return -1; 477 if (a->r.min.x > b->r.min.x) 478 return 1; 479 if (a->r.min.x < b->r.min.x) 480 return -1; 481 return 0; 482 } 483 484 /* compare x-coords only */ 485 static int 486 tkfcmpx(void *ap, void *bp) 487 { 488 TkWinfo *a = ap, *b = bp; 489 return a->r.min.x - b->r.min.x; 490 } 491 492 /* compare y-coords only */ 493 static int 494 tkfcmpy(void *ap, void *bp) 495 { 496 TkWinfo *a = ap, *b = bp; 497 return a->r.min.y - b->r.min.y; 498 } 499 500 static void 501 tkfintervalintersect(int min1, int max1, int min2, int max2, int *min, int *max) 502 { 503 if (min1 < min2) 504 min1 = min2; 505 if (max1 > max2) 506 max1 = max2; 507 if (max1 > min1) { 508 *min = min1; 509 *max = max1; 510 } else 511 *max = *min; /* no intersection */ 512 } 513 514 void 515 tksortfocusorder(TkWinfo *inf, int n) 516 { 517 int i; 518 Rectangle overlap, r; 519 int (*cmpfn)(void*, void*); 520 521 overlap = inf[0].r; 522 for (i = 0; i < n; i++) { 523 r = inf[i].r; 524 tkfintervalintersect(overlap.min.x, overlap.max.x, 525 r.min.x, r.max.x, &overlap.min.x, &overlap.max.x); 526 tkfintervalintersect(overlap.min.y, overlap.max.y, 527 r.min.y, r.max.y, &overlap.min.y, &overlap.max.y); 528 } 529 530 if (Dx(overlap) > 0) 531 cmpfn = tkfcmpy; 532 else if (Dy(overlap) > 0) 533 cmpfn = tkfcmpx; 534 else 535 cmpfn = tkfcmpgen; 536 537 qsort(inf, n, sizeof(*inf), cmpfn); 538 } 539 540 void 541 tkappendfocusorder(Tk *tk) 542 { 543 TkTop *tkt; 544 tkt = tk->env->top; 545 if (tk->flag & Tktakefocus) 546 tkt->focusorder[tkt->nfocus++] = tk; 547 if (tkmethod[tk->type]->focusorder != nil) 548 tkmethod[tk->type]->focusorder(tk); 549 } 550 551 void 552 tkbuildfocusorder(TkTop *tkt) 553 { 554 Tk *tk; 555 int n; 556 557 if (tkt->focusorder != nil) 558 free(tkt->focusorder); 559 n = 0; 560 for (tk = tkt->root; tk != nil; tk = tk->siblings) 561 if (tk->flag & Tktakefocus) 562 n++; 563 if (n == 0) { 564 tkt->focusorder = nil; 565 return; 566 } 567 568 tkt->focusorder = malloc(sizeof(*tkt->focusorder) * n); 569 tkt->nfocus = 0; 570 if (tkt->focusorder == nil) 571 return; 572 573 tkappendfocusorder(tkt->root); 574 } 575 576 void 577 tkdirtyfocusorder(TkTop *tkt) 578 { 579 free(tkt->focusorder); 580 tkt->focusorder = nil; 581 tkt->nfocus = 0; 582 } 583 584 #define O(t, e) ((long)(&((t*)0)->e)) 585 #define OA(t, e) ((long)(((t*)0)->e)) 586 587 typedef struct TkSee TkSee; 588 struct TkSee { 589 int r[4]; 590 int p[2]; 591 int query; 592 }; 593 594 static 595 TkOption seeopts[] = { 596 "rectangle", OPTfrac, OA(TkSee, r), IAUX(4), 597 "point", OPTfrac, OA(TkSee, p), IAUX(2), 598 "where", OPTbool, O(TkSee, query), nil, 599 nil 600 }; 601 602 char* 603 tkseecmd(TkTop *t, char *arg, char **ret) 604 { 605 TkOptab tko[2]; 606 TkSee opts; 607 TkName *names; 608 Tk *tk; 609 char *e; 610 Rectangle vr; 611 Point vp; 612 613 opts.r[0] = bbnil.min.x; 614 opts.r[1] = bbnil.min.y; 615 opts.r[2] = bbnil.max.x; 616 opts.r[3] = bbnil.max.y; 617 opts.p[0] = bbnil.max.x; 618 opts.p[1] = bbnil.max.y; 619 opts.query = 0; 620 621 tko[0].ptr = &opts; 622 tko[0].optab = seeopts; 623 tko[1].ptr = nil; 624 names = nil; 625 e = tkparse(t, arg, tko, &names); 626 if (e != nil) 627 return e; 628 if (names == nil) 629 return TkBadwp; 630 tk = tklook(t, names->name, 0); 631 tkfreename(names); 632 if (tk == nil) 633 return TkBadwp; 634 if (opts.query) { 635 if (!tkvisiblerect(tk, &vr)) 636 return nil; 637 /* XXX should this be converted into screen coords? */ 638 return tkvalue(ret, "%d %d %d %d", vr.min.x, vr.min.y, vr.max.x, vr.max.y); 639 } 640 vr.min.x = opts.r[0]; 641 vr.min.y = opts.r[1]; 642 vr.max.x = opts.r[2]; 643 vr.max.y = opts.r[3]; 644 vp.x = opts.p[0]; 645 vp.y = opts.p[1]; 646 647 if (eqrect(vr, bbnil)) 648 vr = tkrect(tk, 1); 649 if (eqpt(vp, bbnil.max)) 650 vp = vr.min; 651 tksee(tk, vr, vp); 652 return nil; 653 } 654 655 /* 656 * make rectangle r in widget tk visible if possible; 657 * if not possible, at least make point p visible. 658 */ 659 void 660 tksee(Tk *tk, Rectangle r, Point p) 661 { 662 Point g; 663 //print("tksee %R, %P in %s\n", r, p, tk->name->name); 664 g = Pt(tk->borderwidth, tk->borderwidth); 665 if(tk->parent != nil) { 666 g = addpt(g, tkmethod[tk->parent->type]->relpos(tk)); 667 tk = tk->parent; 668 } else { 669 g.x += tk->act.x; 670 g.y += tk->act.y; 671 tk = tk->master; 672 } 673 r = rectaddpt(r, g); 674 p = addpt(p, g); 675 while (tk != nil) { 676 if (tkmethod[tk->type]->see != nil){ 677 //print("see r %R, p %P in %s\n", r, p, tk->name->name); 678 tkmethod[tk->type]->see(tk, &r, &p); 679 //print("now r %R, p %P\n", r, p); 680 } 681 g = Pt(tk->borderwidth, tk->borderwidth); 682 if (tk->parent != nil) { 683 g = addpt(g, tkmethod[tk->parent->type]->relpos(tk)); 684 tk = tk->parent; 685 } else { 686 g.x += tk->act.x; 687 g.y += tk->act.y; 688 tk = tk->master; 689 } 690 r = rectaddpt(r, g); 691 p = addpt(p, g); 692 } 693 } 694