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 if(event & (TkButton2P|TkButton2R)) 246 v = 2; 247 else if(event & (TkButton3P|TkButton3R)) 248 v = 3; 249 } 250 c += snprint(c, len, "%d", v); 251 break; 252 case 'h': 253 if((event & TkConfigure) == 0) 254 goto def; 255 g = (TkGeom*)data; 256 c += snprint(c, len, "%d", g->height); 257 break; 258 case 's': 259 if((event & TkKey)) 260 c += snprint(c, len, "%d", TKKEY(event)); 261 else if((event & (TkEmouse|TkEnter))) 262 c += snprint(c, len, "%d", m->b); 263 else if((event & TkFocusin)) 264 c += snprint(c, len, "%d", (int)data); 265 else 266 goto def; 267 break; 268 case 'w': 269 if((event & TkConfigure) == 0) 270 goto def; 271 g = (TkGeom*)data; 272 c += snprint(c, len, "%d", g->width); 273 break; 274 case 'x': /* Relative mouse coords */ 275 case 'y': 276 if((event & TkKey) || (event & (TkEmouse|TkEnter)) == 0) 277 goto def; 278 p = tkposn(tk); 279 if(s[-1] == 'x') 280 v = m->x - p.x; 281 else 282 v = m->y - p.y; 283 c += snprint(c, len, "%d", v - tk->borderwidth); 284 break; 285 case 'X': /* Absolute mouse coords */ 286 case 'Y': 287 if((event & TkKey) || (event & TkEmouse) == 0) 288 goto def; 289 c += snprint(c, len, "%d", s[-1] == 'X' ? m->x : m->y); 290 break; 291 case 'A': 292 if((event & TkKey) == 0) 293 goto def; 294 v = TKKEY(event); 295 if(v == '{' || v == '}' || v == '\\') 296 c += snprint(c, len, "\\%C", v); 297 else if(v != '\0') 298 c += snprint(c, len, "%C", v); 299 break; 300 case 'K': 301 if((event & TkKey) == 0) 302 goto def; 303 c += snprint(c, len, "%.4X", TKKEY(event)); 304 break; 305 case 'W': 306 if (tk->name != nil) 307 c += snprint(c, len, "%s", tk->name->name); 308 break; 309 } 310 } 311 *c = '\0'; 312 e = nil; 313 t = tk->env->top; 314 t->execdepth = 0; 315 if(cmd[0] == '|') 316 tkexec(t, cmd+1, nil); 317 else if(cmd[0] != '\0') 318 e = tkexec(t, cmd, nil); 319 t->execdepth = -1; 320 321 if(e == nil) { 322 free(cmd); 323 return; 324 } 325 326 if(tk->name != nil){ 327 char *s; 328 329 if(t->errx[0] != '\0') 330 s = tkerrstr(t, e); 331 else 332 s = e; 333 print("tk: bind command \"%s\": %s: %s\n", tk->name->name, cmd, s); 334 if(s != e) 335 free(s); 336 } 337 free(cmd); 338 } 339 340 char* 341 tkbind(TkTop *t, char *arg, char **ret) 342 { 343 Rune r; 344 Tk *tk; 345 TkAction **ap; 346 int i, mode, event; 347 char *cmd, *tag, *seq; 348 char *e; 349 350 USED(ret); 351 352 tag = mallocz(Tkmaxitem, 0); 353 if(tag == nil) 354 return TkNomem; 355 seq = mallocz(Tkmaxitem, 0); 356 if(seq == nil) { 357 free(tag); 358 return TkNomem; 359 } 360 361 arg = tkword(t, arg, tag, tag+Tkmaxitem, nil); 362 if(tag[0] == '\0') { 363 e = TkBadtg; 364 goto err; 365 } 366 367 arg = tkword(t, arg, seq, seq+Tkmaxitem, nil); 368 if(seq[0] == '<') { 369 event = tkseqparse(seq+1); 370 if(event == -1) { 371 e = TkBadsq; 372 goto err; 373 } 374 } 375 else { 376 chartorune(&r, seq); 377 event = TkKey | r; 378 } 379 if(event == 0) { 380 e = TkBadsq; 381 goto err; 382 } 383 384 arg = tkskip(arg, " \t"); 385 386 mode = TkArepl; 387 if(*arg == '+') { 388 mode = TkAadd; 389 arg++; 390 } 391 else if(*arg == '-'){ 392 mode = TkAsub; 393 arg++; 394 } 395 396 if(*arg == '{') { 397 cmd = tkskip(arg+1, " \t"); 398 if(*cmd == '}') { 399 tk = tklook(t, tag, 0); 400 if(tk == nil) { 401 for(i = 0; ; i++) { 402 if(i >= TKwidgets) { 403 e = TkBadwp; 404 tkerr(t, tag); 405 goto err; 406 } 407 if(strcmp(tag, tkmethod[i]->name) == 0) { 408 ap = &(t->binds[i]); 409 break; 410 } 411 } 412 } 413 else 414 ap = &tk->binds; 415 tkcancel(ap, event); 416 } 417 } 418 419 tkword(t, arg, seq, seq+Tkmaxitem, nil); 420 if(tag[0] == '.') { 421 tk = tklook(t, tag, 0); 422 if(tk == nil) { 423 e = TkBadwp; 424 tkerr(t, tag); 425 goto err; 426 } 427 428 cmd = strdup(seq); 429 if(cmd == nil) { 430 e = TkNomem; 431 goto err; 432 } 433 e = tkaction(&tk->binds, event, TkDynamic, cmd, mode); 434 if(e != nil) 435 goto err; /* tkaction does free(cmd) */ 436 free(tag); 437 free(seq); 438 return nil; 439 } 440 /* documented but doesn't work */ 441 if(strcmp(tag, "all") == 0) { 442 for(tk = t->root; tk; tk = tk->next) { 443 cmd = strdup(seq); 444 if(cmd == nil) { 445 e = TkNomem; 446 goto err; 447 } 448 e = tkaction(&tk->binds, event, TkDynamic, cmd, mode); 449 if(e != nil) 450 goto err; 451 } 452 free(tag); 453 free(seq); 454 return nil; 455 } 456 /* undocumented, probably unused, and doesn't work consistently */ 457 for(i = 0; i < TKwidgets; i++) { 458 if(strcmp(tag, tkmethod[i]->name) == 0) { 459 cmd = strdup(seq); 460 if(cmd == nil) { 461 e = TkNomem; 462 goto err; 463 } 464 e = tkaction(t->binds + i,event, TkDynamic, cmd, mode); 465 if(e != nil) 466 goto err; 467 free(tag); 468 free(seq); 469 return nil; 470 } 471 } 472 473 e = TkBadtg; 474 err: 475 free(tag); 476 free(seq); 477 478 return e; 479 } 480 481 char* 482 tksend(TkTop *t, char *arg, char **ret) 483 { 484 485 TkVar *v; 486 char *var; 487 488 USED(ret); 489 490 var = mallocz(Tkmaxitem, 0); 491 if(var == nil) 492 return TkNomem; 493 494 arg = tkword(t, arg, var, var+Tkmaxitem, nil); 495 v = tkmkvar(t, var, 0); 496 free(var); 497 if(v == nil) 498 return TkBadvr; 499 if(v->type != TkVchan) 500 return TkNotvt; 501 502 arg = tkskip(arg, " \t"); 503 if(tktolimbo(v->value, arg) == 0) 504 return TkMovfw; 505 506 return nil; 507 } 508 509 static Tk* 510 tknextfocus(TkTop *t, int d) 511 { 512 int i, n, j, k; 513 Tk *oldfocus; 514 515 if (t->focusorder == nil) 516 tkbuildfocusorder(t); 517 518 oldfocus = t->ctxt->tkkeygrab; 519 n = t->nfocus; 520 if (n == 0) 521 return oldfocus; 522 for (i = 0; i < n; i++) 523 if (t->focusorder[i] == oldfocus) 524 break; 525 if (i == n) { 526 for (i = 0; i < n; i++) 527 if ((t->focusorder[i]->flag & Tkdisabled) == 0) 528 return t->focusorder[i]; 529 return oldfocus; 530 } 531 for (j = 1; j < n; j++) { 532 k = (i + d * j + n) % n; 533 if ((t->focusorder[k]->flag & Tkdisabled) == 0) 534 return t->focusorder[k]; 535 } 536 return oldfocus; 537 } 538 539 /* our dirty little secret */ 540 static void 541 focusdirty(Tk *tk) 542 { 543 if(tk->highlightwidth > 0){ 544 tk->dirty = tkrect(tk, 1); 545 tkdirty(tk); 546 } 547 } 548 549 void 550 tksetkeyfocus(TkTop *top, Tk *new, int dir) 551 { 552 TkCtxt *c; 553 Tk *old; 554 555 c = top->ctxt; 556 old = c->tkkeygrab; 557 558 if(old == new) 559 return; 560 c->tkkeygrab = new; 561 if(top->focused == 0) 562 return; 563 if(old != nil && old != top->root){ 564 tkdeliver(old, TkFocusout, nil); 565 focusdirty(old); 566 } 567 if(new != nil && new != top->root){ 568 tkdeliver(new, TkFocusin, (void*)dir); 569 focusdirty(new); 570 } 571 } 572 573 void 574 tksetglobalfocus(TkTop *top, int in) 575 { 576 Tk *tk; 577 in = (in != 0); 578 if (in != top->focused){ 579 top->focused = in; 580 tk = top->ctxt->tkkeygrab; 581 if(in){ 582 tkdeliver(top->root, TkFocusin, (void*)0); 583 if(tk != nil && tk != top->root){ 584 tkdeliver(tk, TkFocusin, (void*)0); 585 focusdirty(tk); 586 } 587 }else{ 588 if(tk != nil && tk != top->root){ 589 tkdeliver(tk, TkFocusout, nil); 590 focusdirty(tk); 591 } 592 tkdeliver(top->root, TkFocusout, nil); 593 } 594 } 595 } 596 597 char* 598 tkfocus(TkTop *top, char *arg, char **ret) 599 { 600 Tk *tk; 601 char *wp, *e; 602 int dir, global; 603 TkOptab tko[2]; 604 TkName *names; 605 606 tko[0].ptr = &global; 607 tko[0].optab = focusopts; 608 tko[1].ptr = nil; 609 610 global = 0; 611 612 names = nil; 613 e = tkparse(top, arg, tko, &names); 614 if (e != nil) 615 return e; 616 617 if(names == nil){ 618 if(global) 619 return tkvalue(ret, "%d", top->focused); 620 tk = top->ctxt->tkkeygrab; 621 if (tk != nil && tk->name != nil) 622 return tkvalue(ret, "%s", tk->name->name); 623 return nil; 624 } 625 626 if(global){ 627 tksetglobalfocus(top, atoi(names->name)); 628 return nil; 629 } 630 631 wp = mallocz(Tkmaxitem, 0); 632 if(wp == nil) 633 return TkNomem; 634 635 tkword(top, arg, wp, wp+Tkmaxitem, nil); 636 if (!strcmp(wp, "next")) { 637 tk = tknextfocus(top, 1); /* can only return nil if c->tkkeygrab is already nil */ 638 dir = +1; 639 } else if (!strcmp(wp, "previous")) { 640 tk = tknextfocus(top, -1); 641 dir = -1; 642 } else if(*wp == '\0') { 643 tk = nil; 644 dir = 0; 645 } else { 646 tk = tklook(top, wp, 0); 647 if(tk == nil){ 648 tkerr(top, wp); 649 free(wp); 650 return TkBadwp; 651 } 652 dir = 0; 653 } 654 free(wp); 655 656 tksetkeyfocus(top, tk, dir); 657 return nil; 658 } 659 660 char* 661 tkraise(TkTop *t, char *arg, char **ret) 662 { 663 Tk *tk; 664 char *wp; 665 666 USED(ret); 667 668 wp = mallocz(Tkmaxitem, 0); 669 if(wp == nil) 670 return TkNomem; 671 tkword(t, arg, wp, wp+Tkmaxitem, nil); 672 tk = tklook(t, wp, 0); 673 if(tk == nil){ 674 tkerr(t, wp); 675 free(wp); 676 return TkBadwp; 677 } 678 free(wp); 679 680 if((tk->flag & Tkwindow) == 0) 681 return TkNotwm; 682 683 tkwreq(tk->env->top, "raise %s", tk->name->name); 684 return nil; 685 } 686 687 char* 688 tklower(TkTop *t, char *arg, char **ret) 689 { 690 Tk *tk; 691 char *wp; 692 693 USED(ret); 694 wp = mallocz(Tkmaxitem, 0); 695 if(wp == nil) 696 return TkNomem; 697 tkword(t, arg, wp, wp+Tkmaxitem, nil); 698 tk = tklook(t, wp, 0); 699 if(tk == nil){ 700 tkerr(t, wp); 701 free(wp); 702 return TkBadwp; 703 } 704 free(wp); 705 706 if((tk->flag & Tkwindow) == 0) 707 return TkNotwm; 708 709 tkwreq(tk->env->top, "lower %s", tk->name->name); 710 return nil; 711 } 712 713 char* 714 tkgrab(TkTop *t, char *arg, char **ret) 715 { 716 Tk *tk; 717 TkCtxt *c; 718 char *r, *buf, *wp; 719 720 USED(ret); 721 722 buf = mallocz(Tkmaxitem, 0); 723 if(buf == nil) 724 return TkNomem; 725 726 wp = mallocz(Tkmaxitem, 0); 727 if(wp == nil) { 728 free(buf); 729 return TkNomem; 730 } 731 arg = tkword(t, arg, buf, buf+Tkmaxitem, nil); 732 733 tkword(t, arg, wp, wp+Tkmaxitem, nil); 734 tk = tklook(t, wp, 0); 735 if(tk == nil) { 736 free(buf); 737 tkerr(t, wp); 738 free(wp); 739 return TkBadwp; 740 } 741 free(wp); 742 743 c = t->ctxt; 744 if(strcmp(buf, "release") == 0) { 745 free(buf); 746 if(c->mgrab == tk) 747 tksetmgrab(t, nil); 748 return nil; 749 } 750 if(strcmp(buf, "set") == 0) { 751 free(buf); 752 return tksetmgrab(t, tk); 753 } 754 if(strcmp(buf, "ifunset") == 0) { 755 free(buf); 756 if(c->mgrab == nil) 757 return tksetmgrab(t, tk); 758 return nil; 759 } 760 if(strcmp(buf, "status") == 0) { 761 free(buf); 762 r = "none"; 763 if ((c->mgrab != nil) && (c->mgrab->name != nil)) 764 r = c->mgrab->name->name; 765 return tkvalue(ret, "%s", r); 766 } 767 free(buf); 768 return TkBadcm; 769 } 770 771 char* 772 tkputs(TkTop *t, char *arg, char **ret) 773 { 774 char *buf; 775 776 USED(ret); 777 778 buf = mallocz(Tkmaxitem, 0); 779 if(buf == nil) 780 return TkNomem; 781 tkword(t, arg, buf, buf+Tkmaxitem, nil); 782 print("%s\n", buf); 783 free(buf); 784 return nil; 785 } 786 787 char* 788 tkdestroy(TkTop *t, char *arg, char **ret) 789 { 790 int found, len, isroot; 791 Tk *tk, **l, *next, *slave; 792 char *n, *e, *buf; 793 794 USED(ret); 795 buf = mallocz(Tkmaxitem, 0); 796 if(buf == nil) 797 return TkNomem; 798 e = nil; 799 for(;;) { 800 arg = tkword(t, arg, buf, buf+Tkmaxitem, nil); 801 if(buf[0] == '\0') 802 break; 803 804 len = strlen(buf); 805 found = 0; 806 isroot = (strcmp(buf, ".") == 0); 807 for(tk = t->root; tk; tk = tk->siblings) { 808 if (tk->name != nil) { 809 n = tk->name->name; 810 if(strcmp(buf, n) == 0) { 811 tk->flag |= Tkdestroy; 812 found = 1; 813 } else if(isroot || (strncmp(buf, n, len) == 0 && n[len] == '.')) 814 tk->flag |= Tkdestroy; 815 } 816 } 817 if(!found) { 818 e = TkBadwp; 819 tkerr(t, buf); 820 break; 821 } 822 } 823 free(buf); 824 825 for(tk = t->root; tk; tk = tk->siblings) { 826 if((tk->flag & Tkdestroy) == 0) 827 continue; 828 if(tk->flag & Tkwindow) { 829 tkunmap(tk); 830 if(tk->name != nil && 831 strcmp(tk->name->name, ".") == 0) 832 tk->flag &= ~Tkdestroy; 833 else 834 tkdeliver(tk, TkDestroy, nil); 835 } else 836 tkdeliver(tk, TkDestroy, nil); 837 if(0)print("tkdestroy %q\n", tkname(tk)); 838 if(tk->destroyed != nil) 839 tk->destroyed(tk); 840 tkpackqit(tk->master); 841 tkdelpack(tk); 842 for (slave = tk->slave; slave != nil; slave = next) { 843 next = slave->next; 844 slave->master = nil; 845 slave->next = nil; 846 } 847 tk->slave = nil; 848 if(tk->parent != nil && tk->geom != nil) /* XXX this appears to be bogus */ 849 tk->geom(tk, 0, 0, 0, 0); 850 if(tk->grid){ 851 tkfreegrid(tk->grid); 852 tk->grid = nil; 853 } 854 } 855 tkrunpack(t); 856 857 l = &t->windows; 858 for(tk = t->windows; tk; tk = next) { 859 next = TKobj(TkWin, tk)->next; 860 if(tk->flag & Tkdestroy) { 861 *l = next; 862 continue; 863 } 864 l = &TKobj(TkWin, tk)->next; 865 } 866 l = &t->root; 867 for(tk = t->root; tk; tk = next) { 868 next = tk->siblings; 869 if(tk->flag & Tkdestroy) { 870 *l = next; 871 tkfreeobj(tk); 872 continue; 873 } 874 l = &tk->siblings; 875 } 876 877 return e; 878 } 879 880 char* 881 tkupdatecmd(TkTop *t, char *arg, char **ret) 882 { 883 Tk *tk; 884 int x, y; 885 Rectangle *dr; 886 char buf[Tkmaxitem]; 887 888 USED(ret); 889 890 tkword(t, arg, buf, buf+sizeof(buf), nil); 891 if(strcmp(buf, "-onscreen") == 0){ 892 tk = t->root; 893 dr = &t->screenr; 894 x = tk->act.x; 895 if(x+tk->act.width > dr->max.x) 896 x = dr->max.x - tk->act.width; 897 if(x < 0) 898 x = 0; 899 y = tk->act.y; 900 if(y+tk->act.height > dr->max.y) 901 y = dr->max.y - tk->act.height; 902 if(y < 0) 903 y = 0; 904 tkmovewin(tk, Pt(x, y)); 905 }else if(strcmp(buf, "-disable") == 0){ 906 t->noupdate = 1; 907 }else if(strcmp(buf, "-enable") == 0){ 908 t->noupdate = 0; 909 } 910 return tkupdate(t); 911 } 912 913 char* 914 tkwinfo(TkTop *t, char *arg, char **ret) 915 { 916 Tk *tk; 917 char *cmd, *arg1; 918 919 cmd = mallocz(Tkmaxitem, 0); 920 if(cmd == nil) 921 return TkNomem; 922 923 arg = tkword(t, arg, cmd, cmd+Tkmaxitem, nil); 924 if(strcmp(cmd, "class") == 0) { 925 arg1 = mallocz(Tkmaxitem, 0); 926 if(arg1 == nil) { 927 free(cmd); 928 return TkNomem; 929 } 930 tkword(t, arg, arg1, arg1+Tkmaxitem, nil); 931 tk = tklook(t, arg1, 0); 932 if(tk == nil){ 933 tkerr(t, arg1); 934 free(arg1); 935 free(cmd); 936 return TkBadwp; 937 } 938 free(arg1); 939 free(cmd); 940 return tkvalue(ret, "%s", tkmethod[tk->type]->name); 941 } 942 free(cmd); 943 return TkBadvl; 944 } 945 946 char* 947 tkcursorcmd(TkTop *t, char *arg, char **ret) 948 { 949 char *e; 950 int locked; 951 Display *d; 952 TkCursor c; 953 TkOptab tko[3]; 954 enum {Notset = 0x80000000}; 955 956 c.def = 0; 957 c.p.x = Notset; 958 c.p.y = Notset; 959 c.bit = nil; 960 c.img = nil; 961 962 USED(ret); 963 964 c.def = 0; 965 tko[0].ptr = &c; 966 tko[0].optab = tkcurop; 967 tko[1].ptr = nil; 968 e = tkparse(t, arg, tko, nil); 969 if(e != nil) 970 return e; 971 972 d = t->display; 973 locked = lockdisplay(d); 974 if(c.def) 975 tkcursorswitch(t, nil, nil); 976 if(c.img != nil || c.bit != nil){ 977 e = tkcursorswitch(t, c.bit, c.img); 978 tkimgput(c.img); 979 freeimage(c.bit); 980 } 981 if(e == nil){ 982 if(c.p.x != Notset && c.p.y != Notset) 983 tkcursorset(t, c.p); 984 } 985 if(locked) 986 unlockdisplay(d); 987 return e; 988 } 989 990 char * 991 tkbindings(TkTop *t, Tk *tk, TkEbind *b, int blen) 992 { 993 TkAction *a, **ap; 994 char *cmd, *e; 995 int i; 996 997 e = nil; 998 for(i = 0; e == nil && i < blen; i++) /* default bindings */ { 999 int how = TkArepl; 1000 char *cmd = b[i].cmd; 1001 if(cmd[0] == '+') { 1002 how = TkAadd; 1003 cmd++; 1004 } 1005 else if(cmd[0] == '-'){ 1006 how = TkAsub; 1007 cmd++; 1008 } 1009 e = tkaction(&tk->binds, b[i].event, TkStatic, cmd, how); 1010 } 1011 1012 if(e != nil) 1013 return e; 1014 1015 ap = &tk->binds; 1016 for(a = t->binds[tk->type]; a; a = a->link) { /* user "defaults" */ 1017 cmd = strdup(a->arg); 1018 if(cmd == nil) 1019 return TkNomem; 1020 1021 e = tkaction(ap, a->event, TkDynamic, cmd, 1022 (a->type >> 8) & 0xff); 1023 if(e != nil) 1024 return e; 1025 ap = &(*ap)->link; 1026 } 1027 return nil; 1028 } 1029