ebind.c 17 KB

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