control.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <thread.h>
  5. #include <mouse.h>
  6. #include <keyboard.h>
  7. #include <control.h>
  8. enum /* alts */
  9. {
  10. AKey,
  11. AMouse,
  12. ACtl,
  13. AExit,
  14. NALT
  15. };
  16. static Controlset **controlset;
  17. int ncontrolset;
  18. int ctldeletequits;
  19. char *alignnames[Nalignments] = {
  20. [Aupperleft] = "upperleft",
  21. [Auppercenter] = "uppercenter",
  22. [Aupperright] = "upperright",
  23. [Acenterleft] = "centerleft",
  24. [Acenter] = "center",
  25. [Acenterright] = "centerright",
  26. [Alowerleft] = "lowerleft",
  27. [Alowercenter] = "lowercenter",
  28. [Alowerright] = "lowerright",
  29. };
  30. char *ctltypenames[Ntypes] = {
  31. [Ctlunknown] = "unknown",
  32. [Ctlbox] = "box",
  33. [Ctlbutton] = "button",
  34. [Ctlentry] = "entry",
  35. [Ctlkeyboard] = "keyboard",
  36. [Ctllabel] = "label",
  37. [Ctlmenu] = "menu",
  38. [Ctlradio] = "radio",
  39. [Ctlscribble] = "scribble",
  40. [Ctlslider] = "slider",
  41. [Ctltabs] = "tabs",
  42. [Ctltext] = "text",
  43. [Ctltextbutton] = "textbutton",
  44. [Ctlgroup] = "group", // divider between controls and metacontrols
  45. [Ctlboxbox] = "boxbox",
  46. [Ctlcolumn] = "column",
  47. [Ctlrow] = "row",
  48. [Ctlstack] = "stack",
  49. [Ctltab] = "tab",
  50. };
  51. static void _ctlcmd(Controlset*, char*);
  52. static void _ctlcontrol(Controlset*, char*);
  53. static char*
  54. _mkctlcmd(Control *c, char *fmt, va_list arg)
  55. {
  56. char *name, *p, *both;
  57. name = quotestrdup(c->name);
  58. if(name == nil)
  59. ctlerror("quotestrdup in ctlprint failed");
  60. p = vsmprint(fmt, arg);
  61. if(p == nil){
  62. free(name);
  63. ctlerror("vsmprint1 in ctlprint failed");
  64. }
  65. both = ctlmalloc(strlen(name)+strlen(p)+2);
  66. strcpy(both, name);
  67. strcat(both, " ");
  68. strcat(both, p);
  69. free(name);
  70. free(p);
  71. return both;
  72. }
  73. int
  74. ctlprint(Control *c, char *fmt, ...)
  75. {
  76. int n;
  77. char *p;
  78. va_list arg;
  79. va_start(arg, fmt);
  80. p = _mkctlcmd(c, fmt, arg);
  81. va_end(arg);
  82. n = sendp(c->controlset->ctl, p);
  83. yield();
  84. return n;
  85. }
  86. void
  87. _ctlprint(Control *c, char *fmt, ...)
  88. {
  89. char *p;
  90. va_list arg;
  91. va_start(arg, fmt);
  92. p = _mkctlcmd(c, fmt, arg);
  93. va_end(arg);
  94. _ctlcmd(c->controlset, p);
  95. free(p);
  96. }
  97. int
  98. _ctllookup(char *s, char *tab[], int ntab)
  99. {
  100. int i;
  101. for(i=0; i<ntab && tab[i] != nil; i++)
  102. if(strcmp(s, tab[i]) == 0)
  103. return i;
  104. return -1;
  105. }
  106. static Control*
  107. _newcontrol(Controlset *cs, uint n, char *name, char *type)
  108. {
  109. Control *c;
  110. for(c=cs->controls; c; c=c->next)
  111. if(strcmp(c->name, name) == 0){
  112. werrstr("control %q already defined", name);
  113. return nil;
  114. }
  115. c = ctlmalloc(n);
  116. c->screen = cs->screen;
  117. c->name = ctlstrdup(name);
  118. c->type = _ctllookup(type, ctltypenames, Ntypes);
  119. if (c->type < 0)
  120. ctlerror("unknown type: %s", type);
  121. c->event = chancreate(sizeof(char*), 64);
  122. c->data = chancreate(sizeof(char*), 0);
  123. c->size = Rect(1, 1, _Ctlmaxsize, _Ctlmaxsize);
  124. c->hidden = 0;
  125. c->ctl = nil;
  126. c->mouse = nil;
  127. c->key = nil;
  128. c->exit = nil;
  129. c->setsize = nil;
  130. c->controlset = cs;
  131. c->next = cs->controls;
  132. cs->controls = c;
  133. return c;
  134. }
  135. static void
  136. controlsetthread(void *v)
  137. {
  138. Controlset *cs;
  139. Mouse mouse;
  140. Control *f;
  141. int prevbut, n, i;
  142. Alt alts[NALT+1];
  143. char tmp[64], *str;
  144. Rune buf[2][20], *rp;
  145. cs = v;
  146. snprint(tmp, sizeof tmp, "controlsetthread 0x%p", cs);
  147. threadsetname(tmp);
  148. alts[AKey].c = cs->kbdc;
  149. alts[AKey].v = &rp;
  150. alts[AKey].op = CHANRCV;
  151. alts[AMouse].c = cs->mousec;
  152. alts[AMouse].v = &mouse;
  153. alts[AMouse].op = CHANRCV;
  154. alts[ACtl].c = cs->ctl;
  155. alts[ACtl].v = &str;
  156. alts[ACtl].op = CHANRCV;
  157. alts[AExit].c = cs->csexitc;
  158. alts[AExit].v = nil;
  159. alts[AExit].op = CHANRCV;
  160. alts[NALT].op = CHANEND;
  161. cs->focus = nil;
  162. prevbut=0;
  163. n = 0;
  164. for(;;){
  165. /* toggle so we can receive in one buffer while client processes the other */
  166. alts[AKey].v = buf[n];
  167. rp = buf[n];
  168. n = 1-n;
  169. switch(alt(alts)){
  170. case AKey:
  171. if(ctldeletequits && rp[0]=='\177')
  172. ctlerror("delete");
  173. for(i=1; i<nelem(buf[0])-1; i++)
  174. if(nbrecv(cs->kbdc, rp+i) <= 0)
  175. break;
  176. rp[i] = L'\0';
  177. if(cs->focus && cs->focus->key)
  178. cs->focus->key(cs->focus, rp);
  179. break;
  180. case AMouse:
  181. /* is this a focus change? */
  182. if(prevbut) /* don't change focus if button was down */
  183. goto Send;
  184. if(cs->focus!=nil && cs->focus->hidden == 0 && ptinrect(mouse.xy, cs->focus->rect))
  185. goto Send;
  186. if(cs->clicktotype == 0)
  187. goto Change;
  188. /* click to type: only change if button is down */
  189. if(mouse.buttons == 0)
  190. goto Send;
  191. Change:
  192. /* change of focus */
  193. if(cs->focus != nil)
  194. _ctlprint(cs->focus, "focus 0");
  195. cs->focus = nil;
  196. for(f=cs->actives; f!=nil; f=f->nextactive)
  197. if(f->hidden == 0 && f->mouse && ptinrect(mouse.xy, f->rect)){
  198. cs->focus = f;
  199. _ctlprint(f, "focus 1");
  200. if (f->mouse)
  201. f->mouse(f, &mouse);
  202. break;
  203. }
  204. Send:
  205. if(cs->focus && cs->focus->mouse)
  206. cs->focus->mouse(cs->focus, &mouse);
  207. prevbut=mouse.buttons;
  208. break;
  209. case ACtl:
  210. _ctlcontrol(cs, str);
  211. free(str);
  212. break;
  213. case AExit:
  214. threadexits(nil);
  215. }
  216. }
  217. }
  218. Control*
  219. _createctl(Controlset *cs, char *type, uint size, char *name)
  220. {
  221. Control *c;
  222. c = _newcontrol(cs, size, name, type);
  223. if(c == nil)
  224. ctlerror("can't create %s control %q: %r", type, name);
  225. return c;
  226. }
  227. void
  228. closecontrol(Control *c)
  229. {
  230. Control *prev, *p;
  231. if(c == nil)
  232. return;
  233. if (c == c->controlset->focus)
  234. c->controlset->focus = nil;
  235. if(c->exit)
  236. c->exit(c);
  237. prev = nil;
  238. for(p=c->controlset->controls; p; p=p->next){
  239. if(p == c)
  240. break;
  241. prev = p;
  242. }
  243. if(p == nil)
  244. ctlerror("closecontrol: no such control %q %p\n", c->name, c);
  245. if(prev == nil)
  246. c->controlset->controls = c->next;
  247. else
  248. prev->next = c->next;
  249. /* is it active? if so, delete from active list */
  250. prev = nil;
  251. for(p=c->controlset->actives; p; p=p->nextactive){
  252. if(p == c)
  253. break;
  254. prev = p;
  255. }
  256. if(p != nil){
  257. if(prev == nil)
  258. c->controlset->actives = c->nextactive;
  259. else
  260. prev->nextactive = c->nextactive;
  261. }
  262. if(!c->wevent)
  263. chanfree(c->event);
  264. if(!c->wdata)
  265. chanfree(c->data);
  266. free(c->name);
  267. free(c->format);
  268. free(c);
  269. }
  270. Control*
  271. controlcalled(char *name)
  272. {
  273. Control *c;
  274. int i;
  275. for(i=0; i<ncontrolset; i++)
  276. for(c=controlset[i]->controls; c; c=c->next)
  277. if(strcmp(c->name, name) == 0)
  278. return c;
  279. return nil;
  280. }
  281. void
  282. ctlerror(char *fmt, ...)
  283. {
  284. va_list arg;
  285. char buf[256];
  286. va_start(arg, fmt);
  287. vfprint(2, fmt, arg);
  288. va_end(arg);
  289. write(2, "\n", 1);
  290. threadexitsall(buf);
  291. }
  292. Rune*
  293. _ctlrunestr(char *s)
  294. {
  295. Rune *r, *ret;
  296. ret = r = ctlmalloc((utflen(s)+1)*sizeof(Rune));
  297. while(*s != '\0')
  298. s += chartorune(r++, s);
  299. *r = L'\0';
  300. return ret;
  301. }
  302. char*
  303. _ctlstrrune(Rune *r)
  304. {
  305. char *s;
  306. s = ctlmalloc(runestrlen(r)*UTFmax+1);
  307. sprint(s, "%S", r);
  308. return s;
  309. }
  310. void*
  311. ctlmalloc(uint n)
  312. {
  313. void *p;
  314. p = mallocz(n, 1);
  315. if(p == nil)
  316. ctlerror("control allocation failed: %r");
  317. return p;
  318. }
  319. void*
  320. ctlrealloc(void *p, uint n)
  321. {
  322. p = realloc(p, n);
  323. if(p == nil)
  324. ctlerror("control reallocation failed: %r");
  325. return p;
  326. }
  327. char*
  328. ctlstrdup(char *s)
  329. {
  330. char *t;
  331. t = strdup(s);
  332. if(t == nil)
  333. ctlerror("control strdup(%q) failed: %r", s);
  334. return t;
  335. }
  336. static void
  337. ctokenize(char *s, CParse *cp)
  338. {
  339. snprint(cp->str, sizeof cp->str, "%s", s);
  340. cp->args = cp->pargs;
  341. cp->nargs = tokenize(s, cp->args, nelem(cp->pargs));
  342. }
  343. static int
  344. ctlparse(CParse *cp, char *s, int hasreceiver)
  345. {
  346. int i;
  347. char *t;
  348. /* keep original string for good error messages */
  349. strncpy(cp->str, s, sizeof cp->str);
  350. cp->str[sizeof cp->str - 1] = '\0';
  351. ctokenize(s, cp);
  352. if(cp->nargs == 0)
  353. return -1;
  354. /* strip leading sender name if present */
  355. cp->sender = nil;
  356. i = strlen(cp->args[0])-1;
  357. if(cp->args[0][i] == ':'){
  358. cp->sender = cp->args[0];
  359. cp->sender[i] = '\0';
  360. cp->args++;
  361. cp->nargs--;
  362. }
  363. if(hasreceiver){
  364. if(cp->nargs-- == 0)
  365. return -1;
  366. cp->receiver = *cp->args++;
  367. }else
  368. cp->receiver = nil;
  369. for(i=0; i<cp->nargs; i++){
  370. t = cp->args[i];
  371. while(*t == '[') /* %R gives [0 0] [1 1]; atoi will stop at closing ] */
  372. t++;
  373. cp->iargs[i] = atoi(t);
  374. }
  375. return cp->nargs;
  376. }
  377. void
  378. _ctlargcount(Control *c, CParse *cp, int n)
  379. {
  380. if(cp->nargs != n)
  381. ctlerror("%q: wrong argument count in '%s'", c->name, cp->str);
  382. }
  383. static void
  384. _ctlcmd(Controlset *cs, char*s)
  385. {
  386. CParse cp;
  387. char *rcvrs[32];
  388. int ircvrs[32], n, i, hit;
  389. Control *c;
  390. // fprint(2, "_ctlcmd: %s\n", s);
  391. cp.args = cp.pargs;
  392. if (ctlparse(&cp, s, 1) < 0)
  393. ctlerror("bad command string: %q", cp.str);
  394. if (cp.nargs == 0 && strcmp(cp.receiver, "sync") == 0){
  395. chanprint(cs->data, "sync");
  396. return;
  397. }
  398. if (cp.nargs == 0)
  399. ctlerror("no command in command string: %q", cp.str);
  400. n = tokenize(cp.receiver, rcvrs, nelem(rcvrs));
  401. // lookup type names: a receiver can be a named type or a named control
  402. for (i = 0; i < n; i++)
  403. ircvrs[i] = _ctllookup(rcvrs[i], ctltypenames, Ntypes);
  404. for(c = cs->controls; c != nil; c = c->next){
  405. /* if a control matches on more than one receiver element,
  406. * make sure it gets processed once; hence loop through controls
  407. * in the outer loop
  408. */
  409. hit = 0;
  410. for (i = 0; i < n; i++)
  411. if(strcmp(c->name, rcvrs[i]) == 0 || c->type == ircvrs[i])
  412. hit++;
  413. if (hit && c->ctl)
  414. c->ctl(c, &cp);
  415. }
  416. }
  417. static void
  418. _ctlcontrol(Controlset *cs, char *s)
  419. {
  420. char *lines[16];
  421. int i, n;
  422. char *l;
  423. // fprint(2, "_ctlcontrol: %s\n", s);
  424. n = gettokens(s, lines, nelem(lines), "\n");
  425. for(i=0; i<n; i++){
  426. l = lines[i];
  427. while(*l==' ' || *l=='\t')
  428. l++;
  429. if(*l != '\0')
  430. _ctlcmd(cs, l);
  431. }
  432. }
  433. Rune*
  434. _ctlgetsnarf(void)
  435. {
  436. int i, n;
  437. char *sn, buf[512];
  438. Rune *snarf;
  439. if(_ctlsnarffd < 0)
  440. return nil;
  441. sn = nil;
  442. i = 0;
  443. seek(_ctlsnarffd, 0, 0);
  444. while((n = read(_ctlsnarffd, buf, sizeof buf)) > 0){
  445. sn = ctlrealloc(sn, i+n+1);
  446. memmove(sn+i, buf, n);
  447. i += n;
  448. sn[i] = 0;
  449. }
  450. snarf = nil;
  451. if(i > 0){
  452. snarf = _ctlrunestr(sn);
  453. free(sn);
  454. }
  455. return snarf;
  456. }
  457. void
  458. _ctlputsnarf(Rune *snarf)
  459. {
  460. int fd, i, n, nsnarf;
  461. if(_ctlsnarffd<0 || snarf[0]==0)
  462. return;
  463. fd = open("/dev/snarf", OWRITE);
  464. if(fd < 0)
  465. return;
  466. nsnarf = runestrlen(snarf);
  467. /* snarf buffer could be huge, so fprint will truncate; do it in blocks */
  468. for(i=0; i<nsnarf; i+=n){
  469. n = nsnarf-i;
  470. if(n >= 256)
  471. n = 256;
  472. if(fprint(fd, "%.*S", n, snarf+i) < 0)
  473. break;
  474. }
  475. close(fd);
  476. }
  477. int
  478. _ctlalignment(char *s)
  479. {
  480. int i;
  481. i = _ctllookup(s, alignnames, Nalignments);
  482. if (i < 0)
  483. ctlerror("unknown alignment: %s", s);
  484. return i;
  485. }
  486. Point
  487. _ctlalignpoint(Rectangle r, int dx, int dy, int align)
  488. {
  489. Point p;
  490. p = r.min; /* in case of trouble */
  491. switch(align%3){
  492. case 0: /* left */
  493. p.x = r.min.x;
  494. break;
  495. case 1: /* center */
  496. p.x = r.min.x+(Dx(r)-dx)/2;
  497. break;
  498. case 2: /* right */
  499. p.x = r.max.x-dx;
  500. break;
  501. }
  502. switch((align/3)%3){
  503. case 0: /* top */
  504. p.y = r.min.y;
  505. break;
  506. case 1: /* center */
  507. p.y = r.min.y+(Dy(r)-dy)/2;
  508. break;
  509. case 2: /* bottom */
  510. p.y = r.max.y - dy;
  511. break;
  512. }
  513. return p;
  514. }
  515. void
  516. controlwire(Control *cfrom, char *name, Channel *chan)
  517. {
  518. Channel **p;
  519. p = nil;
  520. if(strcmp(name, "event") == 0){
  521. p = &cfrom->event;
  522. cfrom->wevent = 1;
  523. }else if(strcmp(name, "data") == 0){
  524. p = &cfrom->data;
  525. cfrom->wdata = 1;
  526. }else
  527. ctlerror("%q: unknown controlwire channel %s", cfrom->name, name);
  528. chanfree(*p);
  529. *p = chan;
  530. }
  531. void
  532. _ctlfocus(Control *me, int set)
  533. {
  534. Controlset *cs;
  535. cs = me->controlset;
  536. if(set){
  537. if(cs->focus == me)
  538. return;
  539. if(cs->focus != nil)
  540. _ctlprint(cs->focus, "focus 0");
  541. cs->focus = me;
  542. }else{
  543. if(cs->focus != me)
  544. return;
  545. cs->focus = nil;
  546. }
  547. }
  548. static void
  549. resizethread(void *v)
  550. {
  551. Controlset *cs;
  552. char buf[64];
  553. Alt alts[3];
  554. cs = v;
  555. snprint(buf, sizeof buf, "resizethread0x%p", cs);
  556. threadsetname(buf);
  557. alts[0].c = cs->resizec;
  558. alts[0].v = nil;
  559. alts[0].op = CHANRCV;
  560. alts[1].c = cs->resizeexitc;
  561. alts[1].v = nil;
  562. alts[1].op = CHANRCV;
  563. alts[2].op = CHANEND;
  564. for(;;){
  565. switch(alt(alts)){
  566. case 0:
  567. resizecontrolset(cs);
  568. break;
  569. case 1:
  570. return;
  571. }
  572. }
  573. }
  574. void
  575. activate(Control *a)
  576. {
  577. Control *c;
  578. for(c=a->controlset->actives; c; c=c->nextactive)
  579. if(c == a)
  580. ctlerror("%q already active\n", a->name);
  581. if (a->activate){
  582. a->activate(a, 1);
  583. return;
  584. }
  585. /* prepend */
  586. a->nextactive = a->controlset->actives;
  587. a->controlset->actives = a;
  588. }
  589. void
  590. deactivate(Control *a)
  591. {
  592. Control *c, *prev;
  593. /* if group, first deactivate kids, then self */
  594. if (a->activate){
  595. a->activate(a, 0);
  596. return;
  597. }
  598. prev = nil;
  599. for(c=a->controlset->actives; c; c=c->nextactive){
  600. if(c == a){
  601. if(a->controlset->focus == a)
  602. a->controlset->focus = nil;
  603. if(prev != nil)
  604. prev->nextactive = a->nextactive;
  605. else
  606. a->controlset->actives = a->nextactive;
  607. return;
  608. }
  609. prev = c;
  610. }
  611. ctlerror("%q not active\n", a->name);
  612. }
  613. static struct
  614. {
  615. char *name;
  616. ulong color;
  617. }coltab[] = {
  618. "red", DRed,
  619. "green", DGreen,
  620. "blue", DBlue,
  621. "cyan", DCyan,
  622. "magenta", DMagenta,
  623. "yellow", DYellow,
  624. "paleyellow", DPaleyellow,
  625. "darkyellow", DDarkyellow,
  626. "darkgreen", DDarkgreen,
  627. "palegreen", DPalegreen,
  628. "medgreen", DMedgreen,
  629. "darkblue", DDarkblue,
  630. "palebluegreen", DPalebluegreen,
  631. "paleblue", DPaleblue,
  632. "bluegreen", DBluegreen,
  633. "greygreen", DGreygreen,
  634. "palegreygreen", DPalegreygreen,
  635. "yellowgreen", DYellowgreen,
  636. "medblue", DMedblue,
  637. "greyblue", DGreyblue,
  638. "palegreyblue", DPalegreyblue,
  639. "purpleblue", DPurpleblue,
  640. nil, 0
  641. };
  642. void
  643. initcontrols(void)
  644. {
  645. int i;
  646. Image *im;
  647. quotefmtinstall();
  648. namectlimage(display->opaque, "opaque");
  649. namectlimage(display->transparent, "transparent");
  650. namectlimage(display->white, "white");
  651. namectlimage(display->black, "black");
  652. for(i=0; coltab[i].name!=nil; i++){
  653. im = allocimage(display, Rect(0,0,1,1), RGB24, 1, coltab[i].color);
  654. namectlimage(im, coltab[i].name);
  655. }
  656. namectlfont(font, "font");
  657. _ctlsnarffd = open("/dev/snarf", OREAD);
  658. }
  659. Controlset*
  660. newcontrolset(Image *im, Channel *kbdc, Channel *mousec, Channel *resizec)
  661. {
  662. Controlset *cs;
  663. if(im == nil)
  664. im = screen;
  665. if((mousec==nil && resizec!=nil) || (mousec!=nil && resizec==nil))
  666. ctlerror("must specify either or both of mouse and resize channels");
  667. cs = ctlmalloc(sizeof(Controlset));
  668. cs->screen = im;
  669. if(kbdc == nil){
  670. cs->keyboardctl = initkeyboard(nil);
  671. if(cs->keyboardctl == nil)
  672. ctlerror("can't initialize keyboard: %r");
  673. kbdc = cs->keyboardctl->c;
  674. }
  675. cs ->kbdc = kbdc;
  676. if(mousec == nil){
  677. cs->mousectl = initmouse(nil, im);
  678. if(cs->mousectl == nil)
  679. ctlerror("can't initialize mouse: %r");
  680. mousec = cs->mousectl->c;
  681. resizec = cs->mousectl->resizec;
  682. }
  683. cs->mousec = mousec;
  684. cs->resizec = resizec;
  685. cs->ctl = chancreate(sizeof(char*), 64); /* buffer to prevent deadlock */
  686. cs->data = chancreate(sizeof(char*), 0);
  687. cs->resizeexitc = chancreate(sizeof(int), 0);
  688. cs->csexitc = chancreate(sizeof(int), 0);
  689. threadcreate(resizethread, cs, 32*1024);
  690. threadcreate(controlsetthread, cs, 32*1024);
  691. controlset = ctlrealloc(controlset, (ncontrolset+1)*sizeof(Controlset*));
  692. controlset[ncontrolset++] = cs;
  693. return cs;
  694. }
  695. void
  696. closecontrolset(Controlset *cs)
  697. {
  698. int i;
  699. sendul(cs->resizeexitc, 0);
  700. chanfree(cs->resizeexitc);
  701. sendul(cs->csexitc, 0);
  702. chanfree(cs->csexitc);
  703. chanfree(cs->ctl);
  704. chanfree(cs->data);
  705. for(i=0; i<ncontrolset; i++)
  706. if(cs == controlset[i]){
  707. memmove(controlset+i, controlset+i+1, (ncontrolset-(i+1))*sizeof(Controlset*));
  708. ncontrolset--;
  709. goto Found;
  710. }
  711. if(i == ncontrolset)
  712. ctlerror("closecontrolset: control set not found");
  713. Found:
  714. while(cs->controls != nil)
  715. closecontrol(cs->controls);
  716. }