1 #include "lib9.h" 2 #include "draw.h" 3 #include "tk.h" 4 #include <kernel.h> 5 #include <interp.h> 6 7 enum 8 { 9 Cmask, 10 Cctl, 11 Ckey, 12 Cbp, 13 Cbr, 14 }; 15 16 struct 17 { 18 char* event; 19 int mask; 20 int action; 21 } etab[] = 22 { 23 "Motion", TkMotion, Cmask, 24 "Double", TkDouble, Cmask, 25 "Map", TkMap, Cmask, 26 "Unmap", TkUnmap, Cmask, 27 "Destroy", TkDestroy, Cmask, 28 "Enter", TkEnter, Cmask, 29 "Leave", TkLeave, Cmask, 30 "FocusIn", TkFocusin, Cmask, 31 "FocusOut", TkFocusout, Cmask, 32 "Configure", TkConfigure, Cmask, 33 "Control", 0, Cctl, 34 "Key", 0, Ckey, 35 "KeyPress", 0, Ckey, 36 "Button", 0, Cbp, 37 "ButtonPress", 0, Cbp, 38 "ButtonRelease", 0, Cbr, 39 }; 40 41 static 42 TkOption tkcurop[] = 43 { 44 "x", OPTdist, O(TkCursor, p.x), nil, 45 "y", OPTdist, O(TkCursor, p.y), nil, 46 "bitmap", OPTbmap, O(TkCursor, bit), nil, 47 "image", OPTimag, O(TkCursor, img), nil, 48 "default", OPTbool, O(TkCursor, def), nil, 49 nil 50 }; 51 52 static 53 TkOption focusopts[] = { 54 "global", OPTbool, 0, nil, 55 nil 56 }; 57 58 static char* 59 tkseqitem(char *buf, char *arg) 60 { 61 while(*arg && (*arg == ' ' || *arg == '-')) 62 arg++; 63 while(*arg && *arg != ' ' && *arg != '-' && *arg != '>') 64 *buf++ = *arg++; 65 *buf = '\0'; 66 return arg; 67 } 68 69 static char* 70 tkseqkey(Rune *r, char *arg) 71 { 72 char *narg; 73 74 while(*arg && (*arg == ' ' || *arg == '-')) 75 arg++; 76 if (*arg == '\\') { 77 if (*++arg == '\0') { 78 *r = 0; 79 return arg; 80 } 81 } else if (*arg == '\0' || *arg == '>' || *arg == '-') { 82 *r = 0; 83 return arg; 84 } 85 narg = arg + chartorune(r, arg); 86 return narg; 87 } 88 89 int 90 tkseqparse(char *seq) 91 { 92 Rune r; 93 int i, event; 94 char *buf; 95 96 buf = mallocz(Tkmaxitem, 0); 97 if(buf == nil) 98 return -1; 99 100 event = 0; 101 102 while(*seq && *seq != '>') { 103 seq = tkseqitem(buf, seq); 104 105 for(i = 0; i < nelem(etab); i++) 106 if(strcmp(buf, etab[i].event) == 0) 107 break; 108 109 if(i >= nelem(etab)) { 110 seq = tkextnparseseq(buf, seq, &event); 111 if (seq == nil) { 112 free(buf); 113 return -1; 114 } 115 continue; 116 } 117 118 119 switch(etab[i].action) { 120 case Cmask: 121 event |= etab[i].mask; 122 break; 123 case Cctl: 124 seq = tkseqkey(&r, seq); 125 if(r == 0) { 126 free(buf); 127 return -1; 128 } 129 if(r <= '~') 130 r &= 0x1f; 131 event |= TkKey|TKKEY(r); 132 break; 133 case Ckey: 134 seq = tkseqkey(&r, seq); 135 if(r != 0) 136 event |= TKKEY(r); 137 event |= TkKey; 138 break; 139 case Cbp: 140 seq = tkseqitem(buf, seq); 141 switch(buf[0]) { 142 default: 143 free(buf); 144 return -1; 145 case '\0': 146 event |= TkEpress; 147 break; 148 case '1': 149 event |= TkButton1P; 150 break; 151 case '2': 152 event |= TkButton2P; 153 break; 154 case '3': 155 event |= TkButton3P; 156 break; 157 case '4': 158 event |= TkButton4P; 159 break; 160 case '5': 161 event |= TkButton5P; 162 break; 163 case '6': 164 event |= TkButton6P; 165 break; 166 } 167 break; 168 case Cbr: 169 seq = tkseqitem(buf, seq); 170 switch(buf[0]) { 171 default: 172 free(buf); 173 return -1; 174 case '\0': 175 event |= TkErelease; 176 break; 177 case '1': 178 event |= TkButton1R; 179 break; 180 case '2': 181 event |= TkButton2R; 182 break; 183 case '3': 184 event |= TkButton3R; 185 break; 186 case '4': 187 event |= TkButton4R; 188 break; 189 case '5': 190 event |= TkButton5R; 191 break; 192 case '6': 193 event |= TkButton6R; 194 break; 195 } 196 break; 197 } 198 } 199 free(buf); 200 return event; 201 } 202 203 void 204 tkcmdbind(Tk *tk, int event, char *s, void *data) 205 { 206 Point p; 207 TkMouse *m; 208 TkGeom *g; 209 int v, len; 210 char *e, *c, *ec, *cmd; 211 TkTop *t; 212 213 if(s == nil) 214 return; 215 cmd = malloc(2*Tkmaxitem); 216 if (cmd == nil) { 217 print("tk: bind command \"%s\": %s\n", 218 tk->name ? tk->name->name : "(noname)", TkNomem); 219 return; 220 } 221 222 m = (TkMouse*)data; 223 c = cmd; 224 ec = cmd+2*Tkmaxitem-1; 225 while(*s && c < ec) { 226 if(*s != '%') { 227 *c++ = *s++; 228 continue; 229 } 230 s++; 231 len = ec-c; 232 switch(*s++) { 233 def: 234 default: 235 *c++ = s[-1]; 236 break; 237 case '%': 238 *c++ = '%'; 239 break; 240 case 'b': 241 v = 0; 242 if (!(event & TkKey)) { 243 if(event & (TkButton1P|TkButton1R)) 244 v = 1; 245 else 246 if(event & (TkButton2P|TkButton2R)) 247 v = 2; 248 else 249 if(event & (TkButton3P|TkButton3R)) 250 v = 3; 251 } 252 c += snprint(c, len, "%d", v); 253 break; 254 case 'h': 255 if((event & TkConfigure) == 0) 256 goto def; 257 g = (TkGeom*)data; 258 c += snprint(c, len, "%d", g->height); 259 break; 260 case 's': 261 if((event & TkKey)) 262 c += snprint(c, len, "%d", TKKEY(event)); 263 else 264 if((event & (TkEmouse|TkEnter))) 265 c += snprint(c, len, "%d", m->b); 266 else 267 if((event & TkFocusin)) 268 c += snprint(c, len, "%d", (int)data); 269 else 270 goto def; 271 break; 272 case 'w': 273 if((event & TkConfigure) == 0) 274 goto def; 275 g = (TkGeom*)data; 276 c += snprint(c, len, "%d", g->width); 277 break; 278 case 'x': /* Relative mouse coords */ 279 case 'y': 280 if((event & TkKey) || (event & (TkEmouse|TkEnter)) == 0) 281 goto def; 282 p = tkposn(tk); 283 if(s[-1] == 'x') 284 v = m->x - p.x; 285 else 286 v = m->y - p.y; 287 c += snprint(c, len, "%d", v - tk->borderwidth); 288 break; 289 case 'X': /* Absolute mouse coords */ 290 case 'Y': 291 if((event & TkKey) || (event & TkEmouse) == 0) 292 goto def; 293 c += snprint(c, len, "%d", s[-1] == 'X' ? m->x : m->y); 294 break; 295 case 'A': 296 if((event & TkKey) == 0) 297 goto def; 298 v = TKKEY(event); 299 if(v == '{' || v == '}' || v == '\\') 300 c += snprint(c, len, "\\%C", v); 301 else 302 if(v != '\0') 303 c += snprint(c, len, "%C", v); 304 break; 305 case 'K': 306 if((event & TkKey) == 0) 307 goto def; 308 c += snprint(c, len, "%.4X", TKKEY(event)); 309 break; 310 case 'W': 311 if (tk->name != nil) 312 c += snprint(c, len, "%s", tk->name->name); 313 break; 314 } 315 } 316 *c = '\0'; 317 e = nil; 318 t = tk->env->top; 319 t->execdepth = 0; 320 if(cmd[0] == '|') 321 tkexec(t, cmd+1, nil); 322 else 323 if(cmd[0] != '\0') 324 e = tkexec(t, cmd, nil); 325 t->execdepth = -1; 326 327 if(e == nil) { 328 free(cmd); 329 return; 330 } 331 332 if(tk->name != nil){ 333 char *s; 334 335 if(t->errx[0] != '\0') 336 s = tkerrstr(t, e); 337 else 338 s = e; 339 print("tk: bind command \"%s\": %s: %s\n", tk->name->name, cmd, s); 340 if(s != e) 341 free(s); 342 } 343 free(cmd); 344 } 345 346 char* 347 tkbind(TkTop *t, char *arg, char **ret) 348 { 349 Rune r; 350 Tk *tk; 351 TkAction **ap; 352 int i, mode, event; 353 char *cmd, *tag, *seq; 354 char *e; 355 356 USED(ret); 357 358 tag = mallocz(Tkmaxitem, 0); 359 if(tag == nil) 360 return TkNomem; 361 seq = mallocz(Tkmaxitem, 0); 362 if(seq == nil) { 363 free(tag); 364 return TkNomem; 365 } 366 367 arg = tkword(t, arg, tag, tag+Tkmaxitem, nil); 368 if(tag[0] == '\0') { 369 e = TkBadtg; 370 goto err; 371 } 372 373 arg = tkword(t, arg, seq, seq+Tkmaxitem, nil); 374 if(seq[0] == '<') { 375 event = tkseqparse(seq+1); 376 if(event == -1) { 377 e = TkBadsq; 378 goto err; 379 } 380 } 381 else { 382 chartorune(&r, seq); 383 event = TkKey | r; 384 } 385 if(event == 0) { 386 e = TkBadsq; 387 goto err; 388 } 389 390 arg = tkskip(arg, " \t"); 391 392 mode = TkArepl; 393 if(*arg == '+') { 394 mode = TkAadd; 395 arg++; 396 } 397 else if(*arg == '-'){ 398 mode = TkAsub; 399 arg++; 400 } 401 402 if(*arg == '{') { 403 cmd = tkskip(arg+1, " \t"); 404 if(*cmd == '}') { 405 tk = tklook(t, tag, 0); 406 if(tk == nil) { 407 for(i = 0; ; i++) { 408 if(i >= TKwidgets) { 409 e = TkBadwp; 410 tkerr(t, tag); 411 goto err; 412 } 413 if(strcmp(tag, tkmethod[i]->name) == 0) { 414 ap = &(t->binds[i]); 415 break; 416 } 417 } 418 } 419 else 420 ap = &tk->binds; 421 tkcancel(ap, event); 422 } 423 } 424 425 tkword(t, arg, seq, seq+Tkmaxitem, nil); 426 if(tag[0] == '.') { 427 tk = tklook(t, tag, 0); 428 if(tk == nil) { 429 e = TkBadwp; 430 tkerr(t, tag); 431 goto err; 432 } 433 434 cmd = strdup(seq); 435 if(cmd == nil) { 436 e = TkNomem; 437 goto err; 438 } 439 e = tkaction(&tk->binds, event, TkDynamic, cmd, mode); 440 if(e != nil) 441 goto err; /* tkaction does free(cmd) */ 442 free(tag); 443 free(seq); 444 return nil; 445 } 446 /* documented but doesn't work */ 447 if(strcmp(tag, "all") == 0) { 448 for(tk = t->root; tk; tk = tk->next) { 449 cmd = strdup(seq); 450 if(cmd == nil) { 451 e = TkNomem; 452 goto err; 453 } 454 e = tkaction(&tk->binds, event, TkDynamic, cmd, mode); 455 if(e != nil) 456 goto err; 457 } 458 free(tag); 459 free(seq); 460 return nil; 461 } 462 /* undocumented, probably unused, and doesn't work consistently */ 463 for(i = 0; i < TKwidgets; i++) { 464 if(strcmp(tag, tkmethod[i]->name) == 0) { 465 cmd = strdup(seq); 466 if(cmd == nil) { 467 e = TkNomem; 468 goto err; 469 } 470 e = tkaction(t->binds + i,event, TkDynamic, cmd, mode); 471 if(e != nil) 472 goto err; 473 free(tag); 474 free(seq); 475 return nil; 476 } 477 } 478 479 e = TkBadtg; 480 err: 481 free(tag); 482 free(seq); 483 484 return e; 485 } 486 487 char* 488 tksend(TkTop *t, char *arg, char **ret) 489 { 490 491 TkVar *v; 492 char *var; 493 494 USED(ret); 495 496 var = mallocz(Tkmaxitem, 0); 497 if(var == nil) 498 return TkNomem; 499 500 arg = tkword(t, arg, var, var+Tkmaxitem, nil); 501 v = tkmkvar(t, var, 0); 502 free(var); 503 if(v == nil) 504 return TkBadvr; 505 if(v->type != TkVchan) 506 return TkNotvt; 507 508 arg = tkskip(arg, " \t"); 509 if(tktolimbo(v->value, arg) == 0) 510 return TkMovfw; 511 512 return nil; 513 } 514 515 static Tk* 516 tknextfocus(TkTop *t, int d) 517 { 518 int i, n, j, k; 519 Tk *oldfocus; 520 521 if (t->focusorder == nil) 522 tkbuildfocusorder(t); 523 524 oldfocus = t->ctxt->tkkeygrab; 525 n = t->nfocus; 526 if (n == 0) 527 return oldfocus; 528 for (i = 0; i < n; i++) 529 if (t->focusorder[i] == oldfocus) 530 break; 531 if (i == n) { 532 for (i = 0; i < n; i++) 533 if ((t->focusorder[i]->flag & Tkdisabled) == 0) 534 return t->focusorder[i]; 535 return oldfocus; 536 } 537 for (j = 1; j < n; j++) { 538 k = (i + d * j + n) % n; 539 if ((t->focusorder[k]->flag & Tkdisabled) == 0) 540 return t->focusorder[k]; 541 } 542 return oldfocus; 543 } 544 545 /* our dirty little secret */ 546 static void 547 focusdirty(Tk *tk) 548 { 549 if(tk->highlightwidth > 0){ 550 tk->dirty = tkrect(tk, 1); 551 tkdirty(tk); 552 } 553 } 554 555 void 556 tksetkeyfocus(TkTop *top, Tk *new, int dir) 557 { 558 TkCtxt *c; 559 Tk *old; 560 561 c = top->ctxt; 562 old = c->tkkeygrab; 563 564 if(old == new) 565 return; 566 c->tkkeygrab = new; 567 if(top->focused == 0) 568 return; 569 if(old != nil && old != top->root){ 570 tkdeliver(old, TkFocusout, nil); 571 focusdirty(old); 572 } 573 if(new != nil && new != top->root){ 574 tkdeliver(new, TkFocusin, (void*)dir); 575 focusdirty(new); 576 } 577 } 578 579 void 580 tksetglobalfocus(TkTop *top, int in) 581 { 582 Tk *tk; 583 in = (in != 0); 584 if (in != top->focused){ 585 top->focused = in; 586 tk = top->ctxt->tkkeygrab; 587 if(in){ 588 tkdeliver(top->root, TkFocusin, (void*)0); 589 if(tk != nil && tk != top->root){ 590 tkdeliver(tk, TkFocusin, (void*)0); 591 focusdirty(tk); 592 } 593 }else{ 594 if(tk != nil && tk != top->root){ 595 tkdeliver(tk, TkFocusout, nil); 596 focusdirty(tk); 597 } 598 tkdeliver(top->root, TkFocusout, nil); 599 } 600 } 601 } 602 603 char* 604 tkfocus(TkTop *top, char *arg, char **ret) 605 { 606 Tk *tk; 607 char *wp, *e; 608 int dir, global; 609 TkOptab tko[2]; 610 TkName *names; 611 612 tko[0].ptr = &global; 613 tko[0].optab = focusopts; 614 tko[1].ptr = nil; 615 616 global = 0; 617 618 names = nil; 619 e = tkparse(top, arg, tko, &names); 620 if (e != nil) 621 return e; 622 623 if(names == nil){ 624 if(global) 625 return tkvalue(ret, "%d", top->focused); 626 tk = top->ctxt->tkkeygrab; 627 if (tk != nil && tk->name != nil) 628 return tkvalue(ret, "%s", tk->name->name); 629 return nil; 630 } 631 632 if(global){ 633 tksetglobalfocus(top, atoi(names->name)); 634 return nil; 635 } 636 637 wp = mallocz(Tkmaxitem, 0); 638 if(wp == nil) 639 return TkNomem; 640 641 tkword(top, arg, wp, wp+Tkmaxitem, nil); 642 if (!strcmp(wp, "next")) { 643 tk = tknextfocus(top, 1); /* can only return nil if c->tkkeygrab is already nil */ 644 dir = +1; 645 } else if (!strcmp(wp, "previous")) { 646 tk = tknextfocus(top, -1); 647 dir = -1; 648 } else if(*wp == '\0') { 649 tk = nil; 650 dir = 0; 651 } else { 652 tk = tklook(top, wp, 0); 653 if(tk == nil){ 654 tkerr(top, wp); 655 free(wp); 656 return TkBadwp; 657 } 658 dir = 0; 659 } 660 free(wp); 661 662 tksetkeyfocus(top, tk, dir); 663 return nil; 664 } 665 666 char* 667 tkraise(TkTop *t, char *arg, char **ret) 668 { 669 Tk *tk; 670 char *wp; 671 672 USED(ret); 673 674 wp = mallocz(Tkmaxitem, 0); 675 if(wp == nil) 676 return TkNomem; 677 tkword(t, arg, wp, wp+Tkmaxitem, nil); 678 tk = tklook(t, wp, 0); 679 if(tk == nil){ 680 tkerr(t, wp); 681 free(wp); 682 return TkBadwp; 683 } 684 free(wp); 685 686 if((tk->flag & Tkwindow) == 0) 687 return TkNotwm; 688 689 tkwreq(tk->env->top, "raise %s", tk->name->name); 690 return nil; 691 } 692 693 char* 694 tklower(TkTop *t, char *arg, char **ret) 695 { 696 Tk *tk; 697 char *wp; 698 699 USED(ret); 700 wp = mallocz(Tkmaxitem, 0); 701 if(wp == nil) 702 return TkNomem; 703 tkword(t, arg, wp, wp+Tkmaxitem, nil); 704 tk = tklook(t, wp, 0); 705 if(tk == nil){ 706 tkerr(t, wp); 707 free(wp); 708 return TkBadwp; 709 } 710 free(wp); 711 712 if((tk->flag & Tkwindow) == 0) 713 return TkNotwm; 714 715 tkwreq(tk->env->top, "lower %s", tk->name->name); 716 return nil; 717 } 718 719 char* 720 tkgrab(TkTop *t, char *arg, char **ret) 721 { 722 Tk *tk; 723 TkCtxt *c; 724 char *r, *buf, *wp; 725 726 USED(ret); 727 728 buf = mallocz(Tkmaxitem, 0); 729 if(buf == nil) 730 return TkNomem; 731 732 wp = mallocz(Tkmaxitem, 0); 733 if(wp == nil) { 734 free(buf); 735 return TkNomem; 736 } 737 arg = tkword(t, arg, buf, buf+Tkmaxitem, nil); 738 739 tkword(t, arg, wp, wp+Tkmaxitem, nil); 740 tk = tklook(t, wp, 0); 741 if(tk == nil) { 742 free(buf); 743 tkerr(t, wp); 744 free(wp); 745 return TkBadwp; 746 } 747 free(wp); 748 749 c = t->ctxt; 750 if(strcmp(buf, "release") == 0) { 751 free(buf); 752 if(c->mgrab == tk) 753 tksetmgrab(t, nil); 754 return nil; 755 } 756 if(strcmp(buf, "set") == 0) { 757 free(buf); 758 return tksetmgrab(t, tk); 759 } 760 if(strcmp(buf, "ifunset") == 0) { 761 free(buf); 762 if(c->mgrab == nil) 763 return tksetmgrab(t, tk); 764 return nil; 765 } 766 if(strcmp(buf, "status") == 0) { 767 free(buf); 768 r = "none"; 769 if ((c->mgrab != nil) && (c->mgrab->name != nil)) 770 r = c->mgrab->name->name; 771 return tkvalue(ret, "%s", r); 772 } 773 free(buf); 774 return TkBadcm; 775 } 776 777 char* 778 tkputs(TkTop *t, char *arg, char **ret) 779 { 780 char *buf; 781 782 USED(ret); 783 784 buf = mallocz(Tkmaxitem, 0); 785 if(buf == nil) 786 return TkNomem; 787 tkword(t, arg, buf, buf+Tkmaxitem, nil); 788 print("%s\n", buf); 789 free(buf); 790 return nil; 791 } 792 793 char* 794 tkdestroy(TkTop *t, char *arg, char **ret) 795 { 796 int found, len, isroot; 797 Tk *tk, **l, *next, *slave; 798 char *n, *e, *buf; 799 800 USED(ret); 801 buf = mallocz(Tkmaxitem, 0); 802 if(buf == nil) 803 return TkNomem; 804 e = nil; 805 for(;;) { 806 arg = tkword(t, arg, buf, buf+Tkmaxitem, nil); 807 if(buf[0] == '\0') 808 break; 809 810 len = strlen(buf); 811 found = 0; 812 isroot = (strcmp(buf, ".") == 0); 813 for(tk = t->root; tk; tk = tk->siblings) { 814 if (tk->name != nil) { 815 n = tk->name->name; 816 if(strcmp(buf, n) == 0) { 817 tk->flag |= Tkdestroy; 818 found = 1; 819 } else if(isroot || (strncmp(buf, n, len) == 0 &&n[len] == '.')) 820 tk->flag |= Tkdestroy; 821 } 822 } 823 if(!found) { 824 e = TkBadwp; 825 tkerr(t, buf); 826 break; 827 } 828 } 829 free(buf); 830 831 for(tk = t->root; tk; tk = tk->siblings) { 832 if((tk->flag & Tkdestroy) == 0) 833 continue; 834 if(tk->flag & Tkwindow) { 835 tkunmap(tk); 836 if((tk->name != nil) 837 && (strcmp(tk->name->name, ".") == 0)) 838 tk->flag &= ~Tkdestroy; 839 else 840 tkdeliver(tk, TkDestroy, nil); 841 } else 842 tkdeliver(tk, TkDestroy, nil); 843 if(tk->destroyed != nil) 844 tk->destroyed(tk); 845 tkpackqit(tk->master); 846 tkdelpack(tk); 847 for (slave = tk->slave; slave != nil; slave = next) { 848 next = slave->next; 849 slave->master = nil; 850 slave->next = nil; 851 } 852 tk->slave = nil; 853 if(tk->parent != nil && tk->geom != nil) /* XXX this appears to be bogus */ 854 tk->geom(tk, 0, 0, 0, 0); 855 if(tk->grid){ 856 tkfreegrid(tk->grid); 857 tk->grid = nil; 858 } 859 } 860 tkrunpack(t); 861 862 l = &t->windows; 863 for(tk = t->windows; tk; tk = next) { 864 next = TKobj(TkWin, tk)->next; 865 if(tk->flag & Tkdestroy) { 866 *l = next; 867 continue; 868 } 869 l = &TKobj(TkWin, tk)->next; 870 } 871 l = &t->root; 872 for(tk = t->root; tk; tk = next) { 873 next = tk->siblings; 874 if(tk->flag & Tkdestroy) { 875 *l = next; 876 tkfreeobj(tk); 877 continue; 878 } 879 l = &tk->siblings; 880 } 881 882 return e; 883 } 884 885 char* 886 tkupdatecmd(TkTop *t, char *arg, char **ret) 887 { 888 Tk *tk; 889 int x, y; 890 Rectangle *dr; 891 char buf[Tkmaxitem]; 892 893 USED(ret); 894 895 tkword(t, arg, buf, buf+sizeof(buf), nil); 896 if(strcmp(buf, "-onscreen") == 0){ 897 tk = t->root; 898 dr = &t->screenr; 899 x = tk->act.x; 900 if(x+tk->act.width > dr->max.x) 901 x = dr->max.x - tk->act.width; 902 if(x < 0) 903 x = 0; 904 y = tk->act.y; 905 if(y+tk->act.height > dr->max.y) 906 y = dr->max.y - tk->act.height; 907 if(y < 0) 908 y = 0; 909 tkmovewin(tk, Pt(x, y)); 910 }else if(strcmp(buf, "-disable") == 0){ 911 t->noupdate = 1; 912 }else if(strcmp(buf, "-enable") == 0){ 913 t->noupdate = 0; 914 } 915 return tkupdate(t); 916 } 917 918 char* 919 tkwinfo(TkTop *t, char *arg, char **ret) 920 { 921 Tk *tk; 922 char *cmd, *arg1; 923 924 cmd = mallocz(Tkmaxitem, 0); 925 if(cmd == nil) 926 return TkNomem; 927 928 arg = tkword(t, arg, cmd, cmd+Tkmaxitem, nil); 929 if(strcmp(cmd, "class") == 0) { 930 arg1 = mallocz(Tkmaxitem, 0); 931 if(arg1 == nil) { 932 free(cmd); 933 return TkNomem; 934 } 935 tkword(t, arg, arg1, arg1+Tkmaxitem, nil); 936 tk = tklook(t, arg1, 0); 937 if(tk == nil){ 938 tkerr(t, arg1); 939 free(arg1); 940 free(cmd); 941 return TkBadwp; 942 } 943 free(arg1); 944 free(cmd); 945 return tkvalue(ret, "%s", tkmethod[tk->type]->name); 946 } 947 free(cmd); 948 return TkBadvl; 949 } 950 951 char* 952 tkcursorcmd(TkTop *t, char *arg, char **ret) 953 { 954 char *e; 955 int locked; 956 Display *d; 957 TkCursor c; 958 TkOptab tko[3]; 959 enum {Notset = 0x80000000}; 960 961 c.def = 0; 962 c.p.x = Notset; 963 c.p.y = Notset; 964 c.bit = nil; 965 c.img = nil; 966 967 USED(ret); 968 969 c.def = 0; 970 tko[0].ptr = &c; 971 tko[0].optab = tkcurop; 972 tko[1].ptr = nil; 973 e = tkparse(t, arg, tko, nil); 974 if(e != nil) 975 return e; 976 977 d = t->display; 978 locked = lockdisplay(d); 979 if(c.def) 980 tkcursorswitch(t, nil, nil); 981 if(c.img != nil || c.bit != nil){ 982 e = tkcursorswitch(t, c.bit, c.img); 983 tkimgput(c.img); 984 freeimage(c.bit); 985 } 986 if(e == nil){ 987 if(c.p.x != Notset && c.p.y != Notset) 988 tkcursorset(t, c.p); 989 } 990 if(locked) 991 unlockdisplay(d); 992 return e; 993 } 994 995 char * 996 tkbindings(TkTop *t, Tk *tk, TkEbind *b, int blen) 997 { 998 TkAction *a, **ap; 999 char *cmd, *e; 1000 int i; 1001 1002 e = nil; 1003 for(i = 0; e == nil && i < blen; i++) /* default bindings */ { 1004 int how = TkArepl; 1005 char *cmd = b[i].cmd; 1006 if(cmd[0] == '+') { 1007 how = TkAadd; 1008 cmd++; 1009 } 1010 else if(cmd[0] == '-'){ 1011 how = TkAsub; 1012 cmd++; 1013 } 1014 e = tkaction(&tk->binds, b[i].event, TkStatic, cmd, how); 1015 } 1016 1017 if(e != nil) 1018 return e; 1019 1020 ap = &tk->binds; 1021 for(a = t->binds[tk->type]; a; a = a->link) { /* user "defaults" */ 1022 cmd = strdup(a->arg); 1023 if(cmd == nil) 1024 return TkNomem; 1025 1026 e = tkaction(ap, a->event, TkDynamic, cmd, 1027 (a->type >> 8) & 0xff); 1028 if(e != nil) 1029 return e; 1030 ap = &(*ap)->link; 1031 } 1032 return nil; 1033 } 1034