control.c 16 KB

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