control.c 15 KB

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