180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
380ee5cbfSDavid du Colombier #include <draw.h>
480ee5cbfSDavid du Colombier #include <thread.h>
580ee5cbfSDavid du Colombier #include <mouse.h>
680ee5cbfSDavid du Colombier #include <keyboard.h>
780ee5cbfSDavid du Colombier #include <control.h>
880ee5cbfSDavid du Colombier
9*6f314b92SDavid du Colombier static int debug = 0;
10*6f314b92SDavid du Colombier
119a747e4fSDavid du Colombier enum /* alts */
129a747e4fSDavid du Colombier {
139a747e4fSDavid du Colombier AKey,
149a747e4fSDavid du Colombier AMouse,
159a747e4fSDavid du Colombier ACtl,
169a747e4fSDavid du Colombier AExit,
179a747e4fSDavid du Colombier NALT
189a747e4fSDavid du Colombier };
199a747e4fSDavid du Colombier
2080ee5cbfSDavid du Colombier static Controlset **controlset;
2180ee5cbfSDavid du Colombier int ncontrolset;
2280ee5cbfSDavid du Colombier int ctldeletequits;
2380ee5cbfSDavid du Colombier
2480ee5cbfSDavid du Colombier char *alignnames[Nalignments] = {
2580ee5cbfSDavid du Colombier [Aupperleft] = "upperleft",
2680ee5cbfSDavid du Colombier [Auppercenter] = "uppercenter",
2780ee5cbfSDavid du Colombier [Aupperright] = "upperright",
2880ee5cbfSDavid du Colombier [Acenterleft] = "centerleft",
2980ee5cbfSDavid du Colombier [Acenter] = "center",
3080ee5cbfSDavid du Colombier [Acenterright] = "centerright",
3180ee5cbfSDavid du Colombier [Alowerleft] = "lowerleft",
3280ee5cbfSDavid du Colombier [Alowercenter] = "lowercenter",
3380ee5cbfSDavid du Colombier [Alowerright] = "lowerright",
3480ee5cbfSDavid du Colombier };
3580ee5cbfSDavid du Colombier
369a747e4fSDavid du Colombier char *ctltypenames[Ntypes] = {
379a747e4fSDavid du Colombier [Ctlunknown] = "unknown",
389a747e4fSDavid du Colombier [Ctlbox] = "box",
399a747e4fSDavid du Colombier [Ctlbutton] = "button",
409a747e4fSDavid du Colombier [Ctlentry] = "entry",
419a747e4fSDavid du Colombier [Ctlkeyboard] = "keyboard",
429a747e4fSDavid du Colombier [Ctllabel] = "label",
439a747e4fSDavid du Colombier [Ctlmenu] = "menu",
449a747e4fSDavid du Colombier [Ctlradio] = "radio",
459a747e4fSDavid du Colombier [Ctlscribble] = "scribble",
469a747e4fSDavid du Colombier [Ctlslider] = "slider",
479a747e4fSDavid du Colombier [Ctltabs] = "tabs",
489a747e4fSDavid du Colombier [Ctltext] = "text",
499a747e4fSDavid du Colombier [Ctltextbutton] = "textbutton",
50*6f314b92SDavid du Colombier [Ctltextbutton3] = "textbutton3",
519a747e4fSDavid du Colombier [Ctlgroup] = "group", // divider between controls and metacontrols
529a747e4fSDavid du Colombier [Ctlboxbox] = "boxbox",
539a747e4fSDavid du Colombier [Ctlcolumn] = "column",
549a747e4fSDavid du Colombier [Ctlrow] = "row",
559a747e4fSDavid du Colombier [Ctlstack] = "stack",
569a747e4fSDavid du Colombier [Ctltab] = "tab",
579a747e4fSDavid du Colombier };
589a747e4fSDavid du Colombier
599a747e4fSDavid du Colombier static void _ctlcmd(Controlset*, char*);
609a747e4fSDavid du Colombier static void _ctlcontrol(Controlset*, char*);
619a747e4fSDavid du Colombier
629a747e4fSDavid du Colombier static char*
_mkctlcmd(Control * c,char * fmt,va_list arg)639a747e4fSDavid du Colombier _mkctlcmd(Control *c, char *fmt, va_list arg)
649a747e4fSDavid du Colombier {
659a747e4fSDavid du Colombier char *name, *p, *both;
669a747e4fSDavid du Colombier
679a747e4fSDavid du Colombier name = quotestrdup(c->name);
689a747e4fSDavid du Colombier if(name == nil)
699a747e4fSDavid du Colombier ctlerror("quotestrdup in ctlprint failed");
709a747e4fSDavid du Colombier p = vsmprint(fmt, arg);
719a747e4fSDavid du Colombier if(p == nil){
729a747e4fSDavid du Colombier free(name);
739a747e4fSDavid du Colombier ctlerror("vsmprint1 in ctlprint failed");
749a747e4fSDavid du Colombier }
759a747e4fSDavid du Colombier both = ctlmalloc(strlen(name)+strlen(p)+2);
769a747e4fSDavid du Colombier strcpy(both, name);
779a747e4fSDavid du Colombier strcat(both, " ");
789a747e4fSDavid du Colombier strcat(both, p);
799a747e4fSDavid du Colombier free(name);
809a747e4fSDavid du Colombier free(p);
819a747e4fSDavid du Colombier return both;
829a747e4fSDavid du Colombier }
839a747e4fSDavid du Colombier
849a747e4fSDavid du Colombier int
ctlprint(Control * c,char * fmt,...)859a747e4fSDavid du Colombier ctlprint(Control *c, char *fmt, ...)
869a747e4fSDavid du Colombier {
879a747e4fSDavid du Colombier int n;
889a747e4fSDavid du Colombier char *p;
899a747e4fSDavid du Colombier va_list arg;
909a747e4fSDavid du Colombier
919a747e4fSDavid du Colombier va_start(arg, fmt);
929a747e4fSDavid du Colombier p = _mkctlcmd(c, fmt, arg);
939a747e4fSDavid du Colombier va_end(arg);
949a747e4fSDavid du Colombier n = sendp(c->controlset->ctl, p);
959a747e4fSDavid du Colombier yield();
969a747e4fSDavid du Colombier return n;
979a747e4fSDavid du Colombier }
989a747e4fSDavid du Colombier
999a747e4fSDavid du Colombier void
_ctlprint(Control * c,char * fmt,...)1009a747e4fSDavid du Colombier _ctlprint(Control *c, char *fmt, ...)
1019a747e4fSDavid du Colombier {
1029a747e4fSDavid du Colombier char *p;
1039a747e4fSDavid du Colombier va_list arg;
1049a747e4fSDavid du Colombier
1059a747e4fSDavid du Colombier va_start(arg, fmt);
1069a747e4fSDavid du Colombier p = _mkctlcmd(c, fmt, arg);
1079a747e4fSDavid du Colombier va_end(arg);
1089a747e4fSDavid du Colombier _ctlcmd(c->controlset, p);
1099a747e4fSDavid du Colombier free(p);
1109a747e4fSDavid du Colombier }
1119a747e4fSDavid du Colombier
1129a747e4fSDavid du Colombier int
_ctllookup(char * s,char * tab[],int ntab)1139a747e4fSDavid du Colombier _ctllookup(char *s, char *tab[], int ntab)
1149a747e4fSDavid du Colombier {
1159a747e4fSDavid du Colombier int i;
1169a747e4fSDavid du Colombier
117*6f314b92SDavid du Colombier for(i=0; i<ntab; i++)
118*6f314b92SDavid du Colombier if(tab[i] != nil && strcmp(s, tab[i]) == 0)
1199a747e4fSDavid du Colombier return i;
1209a747e4fSDavid du Colombier return -1;
1219a747e4fSDavid du Colombier }
1229a747e4fSDavid du Colombier
12380ee5cbfSDavid du Colombier static Control*
_newcontrol(Controlset * cs,uint n,char * name,char * type)1249a747e4fSDavid du Colombier _newcontrol(Controlset *cs, uint n, char *name, char *type)
12580ee5cbfSDavid du Colombier {
12680ee5cbfSDavid du Colombier Control *c;
12780ee5cbfSDavid du Colombier
12880ee5cbfSDavid du Colombier for(c=cs->controls; c; c=c->next)
12980ee5cbfSDavid du Colombier if(strcmp(c->name, name) == 0){
13080ee5cbfSDavid du Colombier werrstr("control %q already defined", name);
13180ee5cbfSDavid du Colombier return nil;
13280ee5cbfSDavid du Colombier }
13380ee5cbfSDavid du Colombier c = ctlmalloc(n);
13480ee5cbfSDavid du Colombier c->screen = cs->screen;
13580ee5cbfSDavid du Colombier c->name = ctlstrdup(name);
1369a747e4fSDavid du Colombier c->type = _ctllookup(type, ctltypenames, Ntypes);
1379a747e4fSDavid du Colombier if (c->type < 0)
1389a747e4fSDavid du Colombier ctlerror("unknown type: %s", type);
139b7b24591SDavid du Colombier c->event = chancreate(sizeof(char*), 64);
14080ee5cbfSDavid du Colombier c->data = chancreate(sizeof(char*), 0);
1419a747e4fSDavid du Colombier c->size = Rect(1, 1, _Ctlmaxsize, _Ctlmaxsize);
1429a747e4fSDavid du Colombier c->hidden = 0;
1439a747e4fSDavid du Colombier c->ctl = nil;
1449a747e4fSDavid du Colombier c->mouse = nil;
1459a747e4fSDavid du Colombier c->key = nil;
1469a747e4fSDavid du Colombier c->exit = nil;
1479a747e4fSDavid du Colombier c->setsize = nil;
14880ee5cbfSDavid du Colombier
14980ee5cbfSDavid du Colombier c->controlset = cs;
15080ee5cbfSDavid du Colombier c->next = cs->controls;
15180ee5cbfSDavid du Colombier cs->controls = c;
15280ee5cbfSDavid du Colombier return c;
15380ee5cbfSDavid du Colombier }
15480ee5cbfSDavid du Colombier
1559a747e4fSDavid du Colombier static void
controlsetthread(void * v)1569a747e4fSDavid du Colombier controlsetthread(void *v)
1579a747e4fSDavid du Colombier {
1589a747e4fSDavid du Colombier Controlset *cs;
1599a747e4fSDavid du Colombier Mouse mouse;
1609a747e4fSDavid du Colombier Control *f;
1619a747e4fSDavid du Colombier int prevbut, n, i;
1629a747e4fSDavid du Colombier Alt alts[NALT+1];
1639a747e4fSDavid du Colombier char tmp[64], *str;
1649a747e4fSDavid du Colombier Rune buf[2][20], *rp;
1659a747e4fSDavid du Colombier
1669a747e4fSDavid du Colombier cs = v;
1679a747e4fSDavid du Colombier snprint(tmp, sizeof tmp, "controlsetthread 0x%p", cs);
1689a747e4fSDavid du Colombier threadsetname(tmp);
1699a747e4fSDavid du Colombier
1709a747e4fSDavid du Colombier alts[AKey].c = cs->kbdc;
1719a747e4fSDavid du Colombier alts[AKey].v = &rp;
1729a747e4fSDavid du Colombier alts[AKey].op = CHANRCV;
1739a747e4fSDavid du Colombier alts[AMouse].c = cs->mousec;
1749a747e4fSDavid du Colombier alts[AMouse].v = &mouse;
1759a747e4fSDavid du Colombier alts[AMouse].op = CHANRCV;
1769a747e4fSDavid du Colombier alts[ACtl].c = cs->ctl;
1779a747e4fSDavid du Colombier alts[ACtl].v = &str;
1789a747e4fSDavid du Colombier alts[ACtl].op = CHANRCV;
1799a747e4fSDavid du Colombier alts[AExit].c = cs->csexitc;
1809a747e4fSDavid du Colombier alts[AExit].v = nil;
1819a747e4fSDavid du Colombier alts[AExit].op = CHANRCV;
1829a747e4fSDavid du Colombier alts[NALT].op = CHANEND;
1839a747e4fSDavid du Colombier
1849a747e4fSDavid du Colombier cs->focus = nil;
1859a747e4fSDavid du Colombier prevbut=0;
1869a747e4fSDavid du Colombier n = 0;
1879a747e4fSDavid du Colombier for(;;){
1889a747e4fSDavid du Colombier /* toggle so we can receive in one buffer while client processes the other */
1899a747e4fSDavid du Colombier alts[AKey].v = buf[n];
1909a747e4fSDavid du Colombier rp = buf[n];
1919a747e4fSDavid du Colombier n = 1-n;
1929a747e4fSDavid du Colombier switch(alt(alts)){
1939a747e4fSDavid du Colombier case AKey:
1949a747e4fSDavid du Colombier if(ctldeletequits && rp[0]=='\177')
1959a747e4fSDavid du Colombier ctlerror("delete");
1969a747e4fSDavid du Colombier for(i=1; i<nelem(buf[0])-1; i++)
1979a747e4fSDavid du Colombier if(nbrecv(cs->kbdc, rp+i) <= 0)
1989a747e4fSDavid du Colombier break;
1999a747e4fSDavid du Colombier rp[i] = L'\0';
2009a747e4fSDavid du Colombier if(cs->focus && cs->focus->key)
2019a747e4fSDavid du Colombier cs->focus->key(cs->focus, rp);
2029a747e4fSDavid du Colombier break;
2039a747e4fSDavid du Colombier case AMouse:
2049a747e4fSDavid du Colombier /* is this a focus change? */
2059a747e4fSDavid du Colombier if(prevbut) /* don't change focus if button was down */
2069a747e4fSDavid du Colombier goto Send;
2079a747e4fSDavid du Colombier if(cs->focus!=nil && cs->focus->hidden == 0 && ptinrect(mouse.xy, cs->focus->rect))
2089a747e4fSDavid du Colombier goto Send;
2099a747e4fSDavid du Colombier if(cs->clicktotype == 0)
2109a747e4fSDavid du Colombier goto Change;
2119a747e4fSDavid du Colombier /* click to type: only change if button is down */
2129a747e4fSDavid du Colombier if(mouse.buttons == 0)
2139a747e4fSDavid du Colombier goto Send;
2149a747e4fSDavid du Colombier Change:
2159a747e4fSDavid du Colombier /* change of focus */
2169a747e4fSDavid du Colombier if(cs->focus != nil)
2179a747e4fSDavid du Colombier _ctlprint(cs->focus, "focus 0");
2189a747e4fSDavid du Colombier cs->focus = nil;
2199a747e4fSDavid du Colombier for(f=cs->actives; f!=nil; f=f->nextactive)
2209a747e4fSDavid du Colombier if(f->hidden == 0 && f->mouse && ptinrect(mouse.xy, f->rect)){
2219a747e4fSDavid du Colombier cs->focus = f;
2229a747e4fSDavid du Colombier _ctlprint(f, "focus 1");
223*6f314b92SDavid du Colombier if (f->mouse) {
224*6f314b92SDavid du Colombier if (debug) fprint(2, "f->mouse %s\n", f->name);
2259a747e4fSDavid du Colombier f->mouse(f, &mouse);
226*6f314b92SDavid du Colombier }
2279a747e4fSDavid du Colombier break;
2289a747e4fSDavid du Colombier }
2299a747e4fSDavid du Colombier Send:
230*6f314b92SDavid du Colombier if(cs->focus && cs->focus->mouse) {
231*6f314b92SDavid du Colombier if (debug) fprint(2, "cs->focus->mouse %s\n", cs->focus->name);
2329a747e4fSDavid du Colombier cs->focus->mouse(cs->focus, &mouse);
233*6f314b92SDavid du Colombier }
2349a747e4fSDavid du Colombier prevbut=mouse.buttons;
2359a747e4fSDavid du Colombier break;
2369a747e4fSDavid du Colombier case ACtl:
2379a747e4fSDavid du Colombier _ctlcontrol(cs, str);
2389a747e4fSDavid du Colombier free(str);
2399a747e4fSDavid du Colombier break;
2409a747e4fSDavid du Colombier case AExit:
2419a747e4fSDavid du Colombier threadexits(nil);
2429a747e4fSDavid du Colombier }
2439a747e4fSDavid du Colombier }
2449a747e4fSDavid du Colombier }
2459a747e4fSDavid du Colombier
24680ee5cbfSDavid du Colombier Control*
_createctl(Controlset * cs,char * type,uint size,char * name)2479a747e4fSDavid du Colombier _createctl(Controlset *cs, char *type, uint size, char *name)
24880ee5cbfSDavid du Colombier {
24980ee5cbfSDavid du Colombier Control *c;
25080ee5cbfSDavid du Colombier
2519a747e4fSDavid du Colombier c = _newcontrol(cs, size, name, type);
25280ee5cbfSDavid du Colombier if(c == nil)
2539a747e4fSDavid du Colombier ctlerror("can't create %s control %q: %r", type, name);
25480ee5cbfSDavid du Colombier return c;
25580ee5cbfSDavid du Colombier }
25680ee5cbfSDavid du Colombier
25780ee5cbfSDavid du Colombier void
closecontrol(Control * c)25880ee5cbfSDavid du Colombier closecontrol(Control *c)
25980ee5cbfSDavid du Colombier {
26080ee5cbfSDavid du Colombier Control *prev, *p;
26180ee5cbfSDavid du Colombier
26280ee5cbfSDavid du Colombier if(c == nil)
26380ee5cbfSDavid du Colombier return;
2649a747e4fSDavid du Colombier if (c == c->controlset->focus)
2659a747e4fSDavid du Colombier c->controlset->focus = nil;
2669a747e4fSDavid du Colombier if(c->exit)
2679a747e4fSDavid du Colombier c->exit(c);
26880ee5cbfSDavid du Colombier
26980ee5cbfSDavid du Colombier prev = nil;
27080ee5cbfSDavid du Colombier for(p=c->controlset->controls; p; p=p->next){
27180ee5cbfSDavid du Colombier if(p == c)
27280ee5cbfSDavid du Colombier break;
27380ee5cbfSDavid du Colombier prev = p;
27480ee5cbfSDavid du Colombier }
27580ee5cbfSDavid du Colombier if(p == nil)
27680ee5cbfSDavid du Colombier ctlerror("closecontrol: no such control %q %p\n", c->name, c);
27780ee5cbfSDavid du Colombier if(prev == nil)
27880ee5cbfSDavid du Colombier c->controlset->controls = c->next;
27980ee5cbfSDavid du Colombier else
28080ee5cbfSDavid du Colombier prev->next = c->next;
28180ee5cbfSDavid du Colombier
28280ee5cbfSDavid du Colombier /* is it active? if so, delete from active list */
28380ee5cbfSDavid du Colombier prev = nil;
28480ee5cbfSDavid du Colombier for(p=c->controlset->actives; p; p=p->nextactive){
28580ee5cbfSDavid du Colombier if(p == c)
28680ee5cbfSDavid du Colombier break;
28780ee5cbfSDavid du Colombier prev = p;
28880ee5cbfSDavid du Colombier }
28980ee5cbfSDavid du Colombier if(p != nil){
29080ee5cbfSDavid du Colombier if(prev == nil)
29180ee5cbfSDavid du Colombier c->controlset->actives = c->nextactive;
29280ee5cbfSDavid du Colombier else
29380ee5cbfSDavid du Colombier prev->nextactive = c->nextactive;
29480ee5cbfSDavid du Colombier }
29580ee5cbfSDavid du Colombier
29680ee5cbfSDavid du Colombier if(!c->wevent)
29780ee5cbfSDavid du Colombier chanfree(c->event);
29880ee5cbfSDavid du Colombier if(!c->wdata)
29980ee5cbfSDavid du Colombier chanfree(c->data);
30080ee5cbfSDavid du Colombier free(c->name);
30180ee5cbfSDavid du Colombier free(c->format);
30280ee5cbfSDavid du Colombier free(c);
30380ee5cbfSDavid du Colombier }
30480ee5cbfSDavid du Colombier
30580ee5cbfSDavid du Colombier Control*
controlcalled(char * name)30680ee5cbfSDavid du Colombier controlcalled(char *name)
30780ee5cbfSDavid du Colombier {
30880ee5cbfSDavid du Colombier Control *c;
30980ee5cbfSDavid du Colombier int i;
31080ee5cbfSDavid du Colombier
31180ee5cbfSDavid du Colombier for(i=0; i<ncontrolset; i++)
31280ee5cbfSDavid du Colombier for(c=controlset[i]->controls; c; c=c->next)
31380ee5cbfSDavid du Colombier if(strcmp(c->name, name) == 0)
31480ee5cbfSDavid du Colombier return c;
31580ee5cbfSDavid du Colombier return nil;
31680ee5cbfSDavid du Colombier }
31780ee5cbfSDavid du Colombier
31880ee5cbfSDavid du Colombier void
ctlerror(char * fmt,...)31980ee5cbfSDavid du Colombier ctlerror(char *fmt, ...)
32080ee5cbfSDavid du Colombier {
32180ee5cbfSDavid du Colombier va_list arg;
32280ee5cbfSDavid du Colombier char buf[256];
32380ee5cbfSDavid du Colombier
32480ee5cbfSDavid du Colombier va_start(arg, fmt);
3259a747e4fSDavid du Colombier vfprint(2, fmt, arg);
32680ee5cbfSDavid du Colombier va_end(arg);
3279a747e4fSDavid du Colombier write(2, "\n", 1);
32880ee5cbfSDavid du Colombier threadexitsall(buf);
32980ee5cbfSDavid du Colombier }
33080ee5cbfSDavid du Colombier
33180ee5cbfSDavid du Colombier Rune*
_ctlrunestr(char * s)33280ee5cbfSDavid du Colombier _ctlrunestr(char *s)
33380ee5cbfSDavid du Colombier {
33480ee5cbfSDavid du Colombier Rune *r, *ret;
33580ee5cbfSDavid du Colombier
33680ee5cbfSDavid du Colombier ret = r = ctlmalloc((utflen(s)+1)*sizeof(Rune));
33780ee5cbfSDavid du Colombier while(*s != '\0')
33880ee5cbfSDavid du Colombier s += chartorune(r++, s);
33980ee5cbfSDavid du Colombier *r = L'\0';
34080ee5cbfSDavid du Colombier return ret;
34180ee5cbfSDavid du Colombier }
34280ee5cbfSDavid du Colombier
34380ee5cbfSDavid du Colombier char*
_ctlstrrune(Rune * r)34480ee5cbfSDavid du Colombier _ctlstrrune(Rune *r)
34580ee5cbfSDavid du Colombier {
34680ee5cbfSDavid du Colombier char *s;
34780ee5cbfSDavid du Colombier s = ctlmalloc(runestrlen(r)*UTFmax+1);
34880ee5cbfSDavid du Colombier sprint(s, "%S", r);
34980ee5cbfSDavid du Colombier return s;
35080ee5cbfSDavid du Colombier }
35180ee5cbfSDavid du Colombier
35280ee5cbfSDavid du Colombier void*
ctlmalloc(uint n)35380ee5cbfSDavid du Colombier ctlmalloc(uint n)
35480ee5cbfSDavid du Colombier {
35580ee5cbfSDavid du Colombier void *p;
35680ee5cbfSDavid du Colombier
35780ee5cbfSDavid du Colombier p = mallocz(n, 1);
35880ee5cbfSDavid du Colombier if(p == nil)
35980ee5cbfSDavid du Colombier ctlerror("control allocation failed: %r");
36080ee5cbfSDavid du Colombier return p;
36180ee5cbfSDavid du Colombier }
36280ee5cbfSDavid du Colombier
36380ee5cbfSDavid du Colombier void*
ctlrealloc(void * p,uint n)36480ee5cbfSDavid du Colombier ctlrealloc(void *p, uint n)
36580ee5cbfSDavid du Colombier {
36680ee5cbfSDavid du Colombier p = realloc(p, n);
36780ee5cbfSDavid du Colombier if(p == nil)
36880ee5cbfSDavid du Colombier ctlerror("control reallocation failed: %r");
36980ee5cbfSDavid du Colombier return p;
37080ee5cbfSDavid du Colombier }
37180ee5cbfSDavid du Colombier
37280ee5cbfSDavid du Colombier char*
ctlstrdup(char * s)37380ee5cbfSDavid du Colombier ctlstrdup(char *s)
37480ee5cbfSDavid du Colombier {
37580ee5cbfSDavid du Colombier char *t;
37680ee5cbfSDavid du Colombier
37780ee5cbfSDavid du Colombier t = strdup(s);
37880ee5cbfSDavid du Colombier if(t == nil)
37980ee5cbfSDavid du Colombier ctlerror("control strdup(%q) failed: %r", s);
38080ee5cbfSDavid du Colombier return t;
38180ee5cbfSDavid du Colombier }
38280ee5cbfSDavid du Colombier
38380ee5cbfSDavid du Colombier static void
ctokenize(char * s,CParse * cp)38480ee5cbfSDavid du Colombier ctokenize(char *s, CParse *cp)
38580ee5cbfSDavid du Colombier {
38680ee5cbfSDavid du Colombier snprint(cp->str, sizeof cp->str, "%s", s);
3879a747e4fSDavid du Colombier cp->args = cp->pargs;
3889a747e4fSDavid du Colombier cp->nargs = tokenize(s, cp->args, nelem(cp->pargs));
38980ee5cbfSDavid du Colombier }
39080ee5cbfSDavid du Colombier
391ac57dd0bSDavid du Colombier static int
ctlparse(CParse * cp,char * s,int hasreceiver)3929a747e4fSDavid du Colombier ctlparse(CParse *cp, char *s, int hasreceiver)
39380ee5cbfSDavid du Colombier {
3949a747e4fSDavid du Colombier int i;
39580ee5cbfSDavid du Colombier char *t;
39680ee5cbfSDavid du Colombier
39780ee5cbfSDavid du Colombier /* keep original string for good error messages */
3989a747e4fSDavid du Colombier strncpy(cp->str, s, sizeof cp->str);
3999a747e4fSDavid du Colombier cp->str[sizeof cp->str - 1] = '\0';
40080ee5cbfSDavid du Colombier ctokenize(s, cp);
40180ee5cbfSDavid du Colombier if(cp->nargs == 0)
40280ee5cbfSDavid du Colombier return -1;
40380ee5cbfSDavid du Colombier /* strip leading sender name if present */
40480ee5cbfSDavid du Colombier cp->sender = nil;
40580ee5cbfSDavid du Colombier i = strlen(cp->args[0])-1;
40680ee5cbfSDavid du Colombier if(cp->args[0][i] == ':'){
40780ee5cbfSDavid du Colombier cp->sender = cp->args[0];
40880ee5cbfSDavid du Colombier cp->sender[i] = '\0';
4099a747e4fSDavid du Colombier cp->args++;
41080ee5cbfSDavid du Colombier cp->nargs--;
41180ee5cbfSDavid du Colombier }
4129a747e4fSDavid du Colombier if(hasreceiver){
4139a747e4fSDavid du Colombier if(cp->nargs-- == 0)
4149a747e4fSDavid du Colombier return -1;
4159a747e4fSDavid du Colombier cp->receiver = *cp->args++;
4169a747e4fSDavid du Colombier }else
4179a747e4fSDavid du Colombier cp->receiver = nil;
4189a747e4fSDavid du Colombier for(i=0; i<cp->nargs; i++){
41980ee5cbfSDavid du Colombier t = cp->args[i];
42080ee5cbfSDavid du Colombier while(*t == '[') /* %R gives [0 0] [1 1]; atoi will stop at closing ] */
42180ee5cbfSDavid du Colombier t++;
42280ee5cbfSDavid du Colombier cp->iargs[i] = atoi(t);
42380ee5cbfSDavid du Colombier }
4249a747e4fSDavid du Colombier return cp->nargs;
42580ee5cbfSDavid du Colombier }
42680ee5cbfSDavid du Colombier
42780ee5cbfSDavid du Colombier void
_ctlargcount(Control * c,CParse * cp,int n)42880ee5cbfSDavid du Colombier _ctlargcount(Control *c, CParse *cp, int n)
42980ee5cbfSDavid du Colombier {
43080ee5cbfSDavid du Colombier if(cp->nargs != n)
43180ee5cbfSDavid du Colombier ctlerror("%q: wrong argument count in '%s'", c->name, cp->str);
43280ee5cbfSDavid du Colombier }
43380ee5cbfSDavid du Colombier
4349a747e4fSDavid du Colombier static void
_ctlcmd(Controlset * cs,char * s)4359a747e4fSDavid du Colombier _ctlcmd(Controlset *cs, char*s)
4369a747e4fSDavid du Colombier {
4379a747e4fSDavid du Colombier CParse cp;
4389a747e4fSDavid du Colombier char *rcvrs[32];
4399a747e4fSDavid du Colombier int ircvrs[32], n, i, hit;
4409a747e4fSDavid du Colombier Control *c;
4419a747e4fSDavid du Colombier
4429a747e4fSDavid du Colombier // fprint(2, "_ctlcmd: %s\n", s);
4439a747e4fSDavid du Colombier cp.args = cp.pargs;
4449a747e4fSDavid du Colombier if (ctlparse(&cp, s, 1) < 0)
4459a747e4fSDavid du Colombier ctlerror("bad command string: %q", cp.str);
4469a747e4fSDavid du Colombier if (cp.nargs == 0 && strcmp(cp.receiver, "sync") == 0){
4479a747e4fSDavid du Colombier chanprint(cs->data, "sync");
4489a747e4fSDavid du Colombier return;
4499a747e4fSDavid du Colombier }
4509a747e4fSDavid du Colombier if (cp.nargs == 0)
4519a747e4fSDavid du Colombier ctlerror("no command in command string: %q", cp.str);
4529a747e4fSDavid du Colombier
4539a747e4fSDavid du Colombier n = tokenize(cp.receiver, rcvrs, nelem(rcvrs));
4549a747e4fSDavid du Colombier
4559a747e4fSDavid du Colombier // lookup type names: a receiver can be a named type or a named control
4569a747e4fSDavid du Colombier for (i = 0; i < n; i++)
4579a747e4fSDavid du Colombier ircvrs[i] = _ctllookup(rcvrs[i], ctltypenames, Ntypes);
4589a747e4fSDavid du Colombier
4599a747e4fSDavid du Colombier for(c = cs->controls; c != nil; c = c->next){
4609a747e4fSDavid du Colombier /* if a control matches on more than one receiver element,
4619a747e4fSDavid du Colombier * make sure it gets processed once; hence loop through controls
4629a747e4fSDavid du Colombier * in the outer loop
4639a747e4fSDavid du Colombier */
4649a747e4fSDavid du Colombier hit = 0;
4659a747e4fSDavid du Colombier for (i = 0; i < n; i++)
4669a747e4fSDavid du Colombier if(strcmp(c->name, rcvrs[i]) == 0 || c->type == ircvrs[i])
4679a747e4fSDavid du Colombier hit++;
4689a747e4fSDavid du Colombier if (hit && c->ctl)
4699a747e4fSDavid du Colombier c->ctl(c, &cp);
4709a747e4fSDavid du Colombier }
4719a747e4fSDavid du Colombier }
4729a747e4fSDavid du Colombier
4739a747e4fSDavid du Colombier static void
_ctlcontrol(Controlset * cs,char * s)4749a747e4fSDavid du Colombier _ctlcontrol(Controlset *cs, char *s)
47580ee5cbfSDavid du Colombier {
47680ee5cbfSDavid du Colombier char *lines[16];
47780ee5cbfSDavid du Colombier int i, n;
47880ee5cbfSDavid du Colombier char *l;
47980ee5cbfSDavid du Colombier
4809a747e4fSDavid du Colombier // fprint(2, "_ctlcontrol: %s\n", s);
4819a747e4fSDavid du Colombier n = gettokens(s, lines, nelem(lines), "\n");
48280ee5cbfSDavid du Colombier for(i=0; i<n; i++){
48380ee5cbfSDavid du Colombier l = lines[i];
48480ee5cbfSDavid du Colombier while(*l==' ' || *l=='\t')
48580ee5cbfSDavid du Colombier l++;
48680ee5cbfSDavid du Colombier if(*l != '\0')
4879a747e4fSDavid du Colombier _ctlcmd(cs, l);
48880ee5cbfSDavid du Colombier }
48980ee5cbfSDavid du Colombier }
49080ee5cbfSDavid du Colombier
49180ee5cbfSDavid du Colombier Rune*
_ctlgetsnarf(void)49280ee5cbfSDavid du Colombier _ctlgetsnarf(void)
49380ee5cbfSDavid du Colombier {
49480ee5cbfSDavid du Colombier int i, n;
49580ee5cbfSDavid du Colombier char *sn, buf[512];
49680ee5cbfSDavid du Colombier Rune *snarf;
49780ee5cbfSDavid du Colombier
49880ee5cbfSDavid du Colombier if(_ctlsnarffd < 0)
49980ee5cbfSDavid du Colombier return nil;
50080ee5cbfSDavid du Colombier sn = nil;
50180ee5cbfSDavid du Colombier i = 0;
50280ee5cbfSDavid du Colombier seek(_ctlsnarffd, 0, 0);
50380ee5cbfSDavid du Colombier while((n = read(_ctlsnarffd, buf, sizeof buf)) > 0){
50480ee5cbfSDavid du Colombier sn = ctlrealloc(sn, i+n+1);
50580ee5cbfSDavid du Colombier memmove(sn+i, buf, n);
50680ee5cbfSDavid du Colombier i += n;
50780ee5cbfSDavid du Colombier sn[i] = 0;
50880ee5cbfSDavid du Colombier }
50980ee5cbfSDavid du Colombier snarf = nil;
51080ee5cbfSDavid du Colombier if(i > 0){
51180ee5cbfSDavid du Colombier snarf = _ctlrunestr(sn);
51280ee5cbfSDavid du Colombier free(sn);
51380ee5cbfSDavid du Colombier }
51480ee5cbfSDavid du Colombier return snarf;
51580ee5cbfSDavid du Colombier }
51680ee5cbfSDavid du Colombier
51780ee5cbfSDavid du Colombier void
_ctlputsnarf(Rune * snarf)51880ee5cbfSDavid du Colombier _ctlputsnarf(Rune *snarf)
51980ee5cbfSDavid du Colombier {
52080ee5cbfSDavid du Colombier int fd, i, n, nsnarf;
52180ee5cbfSDavid du Colombier
52280ee5cbfSDavid du Colombier if(_ctlsnarffd<0 || snarf[0]==0)
52380ee5cbfSDavid du Colombier return;
52480ee5cbfSDavid du Colombier fd = open("/dev/snarf", OWRITE);
52580ee5cbfSDavid du Colombier if(fd < 0)
52680ee5cbfSDavid du Colombier return;
52780ee5cbfSDavid du Colombier nsnarf = runestrlen(snarf);
52880ee5cbfSDavid du Colombier /* snarf buffer could be huge, so fprint will truncate; do it in blocks */
52980ee5cbfSDavid du Colombier for(i=0; i<nsnarf; i+=n){
53080ee5cbfSDavid du Colombier n = nsnarf-i;
53180ee5cbfSDavid du Colombier if(n >= 256)
53280ee5cbfSDavid du Colombier n = 256;
5339a747e4fSDavid du Colombier if(fprint(fd, "%.*S", n, snarf+i) < 0)
53480ee5cbfSDavid du Colombier break;
53580ee5cbfSDavid du Colombier }
53680ee5cbfSDavid du Colombier close(fd);
53780ee5cbfSDavid du Colombier }
53880ee5cbfSDavid du Colombier
53980ee5cbfSDavid du Colombier int
_ctlalignment(char * s)54080ee5cbfSDavid du Colombier _ctlalignment(char *s)
54180ee5cbfSDavid du Colombier {
54280ee5cbfSDavid du Colombier int i;
54380ee5cbfSDavid du Colombier
5449a747e4fSDavid du Colombier i = _ctllookup(s, alignnames, Nalignments);
5459a747e4fSDavid du Colombier if (i < 0)
54680ee5cbfSDavid du Colombier ctlerror("unknown alignment: %s", s);
5479a747e4fSDavid du Colombier return i;
54880ee5cbfSDavid du Colombier }
54980ee5cbfSDavid du Colombier
55080ee5cbfSDavid du Colombier Point
_ctlalignpoint(Rectangle r,int dx,int dy,int align)55180ee5cbfSDavid du Colombier _ctlalignpoint(Rectangle r, int dx, int dy, int align)
55280ee5cbfSDavid du Colombier {
55380ee5cbfSDavid du Colombier Point p;
55480ee5cbfSDavid du Colombier
55580ee5cbfSDavid du Colombier p = r.min; /* in case of trouble */
55680ee5cbfSDavid du Colombier switch(align%3){
55780ee5cbfSDavid du Colombier case 0: /* left */
55880ee5cbfSDavid du Colombier p.x = r.min.x;
55980ee5cbfSDavid du Colombier break;
56080ee5cbfSDavid du Colombier case 1: /* center */
56180ee5cbfSDavid du Colombier p.x = r.min.x+(Dx(r)-dx)/2;
56280ee5cbfSDavid du Colombier break;
56380ee5cbfSDavid du Colombier case 2: /* right */
56480ee5cbfSDavid du Colombier p.x = r.max.x-dx;
56580ee5cbfSDavid du Colombier break;
56680ee5cbfSDavid du Colombier }
56780ee5cbfSDavid du Colombier switch((align/3)%3){
56880ee5cbfSDavid du Colombier case 0: /* top */
56980ee5cbfSDavid du Colombier p.y = r.min.y;
57080ee5cbfSDavid du Colombier break;
57180ee5cbfSDavid du Colombier case 1: /* center */
57280ee5cbfSDavid du Colombier p.y = r.min.y+(Dy(r)-dy)/2;
57380ee5cbfSDavid du Colombier break;
57480ee5cbfSDavid du Colombier case 2: /* bottom */
57580ee5cbfSDavid du Colombier p.y = r.max.y - dy;
57680ee5cbfSDavid du Colombier break;
57780ee5cbfSDavid du Colombier }
57880ee5cbfSDavid du Colombier return p;
57980ee5cbfSDavid du Colombier }
58080ee5cbfSDavid du Colombier
58180ee5cbfSDavid du Colombier void
controlwire(Control * cfrom,char * name,Channel * chan)5829a747e4fSDavid du Colombier controlwire(Control *cfrom, char *name, Channel *chan)
58380ee5cbfSDavid du Colombier {
58480ee5cbfSDavid du Colombier Channel **p;
58580ee5cbfSDavid du Colombier
58680ee5cbfSDavid du Colombier p = nil;
5879a747e4fSDavid du Colombier if(strcmp(name, "event") == 0){
5889a747e4fSDavid du Colombier p = &cfrom->event;
5899a747e4fSDavid du Colombier cfrom->wevent = 1;
5909a747e4fSDavid du Colombier }else if(strcmp(name, "data") == 0){
5919a747e4fSDavid du Colombier p = &cfrom->data;
5929a747e4fSDavid du Colombier cfrom->wdata = 1;
59380ee5cbfSDavid du Colombier }else
5949a747e4fSDavid du Colombier ctlerror("%q: unknown controlwire channel %s", cfrom->name, name);
59580ee5cbfSDavid du Colombier chanfree(*p);
5969a747e4fSDavid du Colombier *p = chan;
59780ee5cbfSDavid du Colombier }
59880ee5cbfSDavid du Colombier
59980ee5cbfSDavid du Colombier void
_ctlfocus(Control * me,int set)6009a747e4fSDavid du Colombier _ctlfocus(Control *me, int set)
60180ee5cbfSDavid du Colombier {
60280ee5cbfSDavid du Colombier Controlset *cs;
60380ee5cbfSDavid du Colombier
6049a747e4fSDavid du Colombier cs = me->controlset;
6059a747e4fSDavid du Colombier if(set){
6069a747e4fSDavid du Colombier if(cs->focus == me)
60780ee5cbfSDavid du Colombier return;
6089a747e4fSDavid du Colombier if(cs->focus != nil)
6099a747e4fSDavid du Colombier _ctlprint(cs->focus, "focus 0");
6109a747e4fSDavid du Colombier cs->focus = me;
6119a747e4fSDavid du Colombier }else{
6129a747e4fSDavid du Colombier if(cs->focus != me)
6139a747e4fSDavid du Colombier return;
6149a747e4fSDavid du Colombier cs->focus = nil;
61580ee5cbfSDavid du Colombier }
61680ee5cbfSDavid du Colombier }
61780ee5cbfSDavid du Colombier
61880ee5cbfSDavid du Colombier static void
resizethread(void * v)61980ee5cbfSDavid du Colombier resizethread(void *v)
62080ee5cbfSDavid du Colombier {
62180ee5cbfSDavid du Colombier Controlset *cs;
62280ee5cbfSDavid du Colombier char buf[64];
62380ee5cbfSDavid du Colombier Alt alts[3];
62480ee5cbfSDavid du Colombier
62580ee5cbfSDavid du Colombier cs = v;
62680ee5cbfSDavid du Colombier snprint(buf, sizeof buf, "resizethread0x%p", cs);
62780ee5cbfSDavid du Colombier threadsetname(buf);
62880ee5cbfSDavid du Colombier
62980ee5cbfSDavid du Colombier alts[0].c = cs->resizec;
63080ee5cbfSDavid du Colombier alts[0].v = nil;
63180ee5cbfSDavid du Colombier alts[0].op = CHANRCV;
63280ee5cbfSDavid du Colombier alts[1].c = cs->resizeexitc;
63380ee5cbfSDavid du Colombier alts[1].v = nil;
63480ee5cbfSDavid du Colombier alts[1].op = CHANRCV;
63580ee5cbfSDavid du Colombier alts[2].op = CHANEND;
63680ee5cbfSDavid du Colombier
63780ee5cbfSDavid du Colombier for(;;){
63880ee5cbfSDavid du Colombier switch(alt(alts)){
63980ee5cbfSDavid du Colombier case 0:
64080ee5cbfSDavid du Colombier resizecontrolset(cs);
64180ee5cbfSDavid du Colombier break;
64280ee5cbfSDavid du Colombier case 1:
64380ee5cbfSDavid du Colombier return;
64480ee5cbfSDavid du Colombier }
64580ee5cbfSDavid du Colombier }
64680ee5cbfSDavid du Colombier }
64780ee5cbfSDavid du Colombier
64880ee5cbfSDavid du Colombier void
activate(Control * a)64980ee5cbfSDavid du Colombier activate(Control *a)
65080ee5cbfSDavid du Colombier {
65180ee5cbfSDavid du Colombier Control *c;
65280ee5cbfSDavid du Colombier
65380ee5cbfSDavid du Colombier for(c=a->controlset->actives; c; c=c->nextactive)
65480ee5cbfSDavid du Colombier if(c == a)
65580ee5cbfSDavid du Colombier ctlerror("%q already active\n", a->name);
6569a747e4fSDavid du Colombier
6579a747e4fSDavid du Colombier if (a->activate){
6589a747e4fSDavid du Colombier a->activate(a, 1);
6599a747e4fSDavid du Colombier return;
6609a747e4fSDavid du Colombier }
6619a747e4fSDavid du Colombier /* prepend */
66280ee5cbfSDavid du Colombier a->nextactive = a->controlset->actives;
66380ee5cbfSDavid du Colombier a->controlset->actives = a;
66480ee5cbfSDavid du Colombier }
66580ee5cbfSDavid du Colombier
66680ee5cbfSDavid du Colombier void
deactivate(Control * a)66780ee5cbfSDavid du Colombier deactivate(Control *a)
66880ee5cbfSDavid du Colombier {
66980ee5cbfSDavid du Colombier Control *c, *prev;
67080ee5cbfSDavid du Colombier
6719a747e4fSDavid du Colombier /* if group, first deactivate kids, then self */
6729a747e4fSDavid du Colombier if (a->activate){
6739a747e4fSDavid du Colombier a->activate(a, 0);
6749a747e4fSDavid du Colombier return;
6759a747e4fSDavid du Colombier }
67680ee5cbfSDavid du Colombier prev = nil;
67780ee5cbfSDavid du Colombier for(c=a->controlset->actives; c; c=c->nextactive){
67880ee5cbfSDavid du Colombier if(c == a){
67980ee5cbfSDavid du Colombier if(a->controlset->focus == a)
68080ee5cbfSDavid du Colombier a->controlset->focus = nil;
68180ee5cbfSDavid du Colombier if(prev != nil)
68280ee5cbfSDavid du Colombier prev->nextactive = a->nextactive;
68380ee5cbfSDavid du Colombier else
68480ee5cbfSDavid du Colombier a->controlset->actives = a->nextactive;
68580ee5cbfSDavid du Colombier return;
68680ee5cbfSDavid du Colombier }
68780ee5cbfSDavid du Colombier prev = c;
68880ee5cbfSDavid du Colombier }
68980ee5cbfSDavid du Colombier ctlerror("%q not active\n", a->name);
69080ee5cbfSDavid du Colombier }
69180ee5cbfSDavid du Colombier
69280ee5cbfSDavid du Colombier static struct
69380ee5cbfSDavid du Colombier {
69480ee5cbfSDavid du Colombier char *name;
69580ee5cbfSDavid du Colombier ulong color;
69680ee5cbfSDavid du Colombier }coltab[] = {
69780ee5cbfSDavid du Colombier "red", DRed,
69880ee5cbfSDavid du Colombier "green", DGreen,
69980ee5cbfSDavid du Colombier "blue", DBlue,
70080ee5cbfSDavid du Colombier "cyan", DCyan,
70180ee5cbfSDavid du Colombier "magenta", DMagenta,
70280ee5cbfSDavid du Colombier "yellow", DYellow,
70380ee5cbfSDavid du Colombier "paleyellow", DPaleyellow,
70480ee5cbfSDavid du Colombier "darkyellow", DDarkyellow,
70580ee5cbfSDavid du Colombier "darkgreen", DDarkgreen,
70680ee5cbfSDavid du Colombier "palegreen", DPalegreen,
70780ee5cbfSDavid du Colombier "medgreen", DMedgreen,
70880ee5cbfSDavid du Colombier "darkblue", DDarkblue,
70980ee5cbfSDavid du Colombier "palebluegreen", DPalebluegreen,
71080ee5cbfSDavid du Colombier "paleblue", DPaleblue,
71180ee5cbfSDavid du Colombier "bluegreen", DBluegreen,
71280ee5cbfSDavid du Colombier "greygreen", DGreygreen,
71380ee5cbfSDavid du Colombier "palegreygreen", DPalegreygreen,
71480ee5cbfSDavid du Colombier "yellowgreen", DYellowgreen,
71580ee5cbfSDavid du Colombier "medblue", DMedblue,
71680ee5cbfSDavid du Colombier "greyblue", DGreyblue,
71780ee5cbfSDavid du Colombier "palegreyblue", DPalegreyblue,
71880ee5cbfSDavid du Colombier "purpleblue", DPurpleblue,
71980ee5cbfSDavid du Colombier nil, 0
72080ee5cbfSDavid du Colombier };
72180ee5cbfSDavid du Colombier
72280ee5cbfSDavid du Colombier void
initcontrols(void)72380ee5cbfSDavid du Colombier initcontrols(void)
72480ee5cbfSDavid du Colombier {
72580ee5cbfSDavid du Colombier int i;
72680ee5cbfSDavid du Colombier Image *im;
72780ee5cbfSDavid du Colombier
72880ee5cbfSDavid du Colombier quotefmtinstall();
72980ee5cbfSDavid du Colombier namectlimage(display->opaque, "opaque");
73080ee5cbfSDavid du Colombier namectlimage(display->transparent, "transparent");
73180ee5cbfSDavid du Colombier namectlimage(display->white, "white");
73280ee5cbfSDavid du Colombier namectlimage(display->black, "black");
73380ee5cbfSDavid du Colombier for(i=0; coltab[i].name!=nil; i++){
73480ee5cbfSDavid du Colombier im = allocimage(display, Rect(0,0,1,1), RGB24, 1, coltab[i].color);
73580ee5cbfSDavid du Colombier namectlimage(im, coltab[i].name);
73680ee5cbfSDavid du Colombier }
73780ee5cbfSDavid du Colombier namectlfont(font, "font");
73880ee5cbfSDavid du Colombier _ctlsnarffd = open("/dev/snarf", OREAD);
73980ee5cbfSDavid du Colombier }
74080ee5cbfSDavid du Colombier
74180ee5cbfSDavid du Colombier Controlset*
newcontrolset(Image * im,Channel * kbdc,Channel * mousec,Channel * resizec)74280ee5cbfSDavid du Colombier newcontrolset(Image *im, Channel *kbdc, Channel *mousec, Channel *resizec)
74380ee5cbfSDavid du Colombier {
74480ee5cbfSDavid du Colombier Controlset *cs;
74580ee5cbfSDavid du Colombier
74680ee5cbfSDavid du Colombier if(im == nil)
74780ee5cbfSDavid du Colombier im = screen;
74880ee5cbfSDavid du Colombier if((mousec==nil && resizec!=nil) || (mousec!=nil && resizec==nil))
74980ee5cbfSDavid du Colombier ctlerror("must specify either or both of mouse and resize channels");
75080ee5cbfSDavid du Colombier
75180ee5cbfSDavid du Colombier cs = ctlmalloc(sizeof(Controlset));
75280ee5cbfSDavid du Colombier cs->screen = im;
75380ee5cbfSDavid du Colombier
75480ee5cbfSDavid du Colombier if(kbdc == nil){
75580ee5cbfSDavid du Colombier cs->keyboardctl = initkeyboard(nil);
75680ee5cbfSDavid du Colombier if(cs->keyboardctl == nil)
75780ee5cbfSDavid du Colombier ctlerror("can't initialize keyboard: %r");
75880ee5cbfSDavid du Colombier kbdc = cs->keyboardctl->c;
75980ee5cbfSDavid du Colombier }
76080ee5cbfSDavid du Colombier cs ->kbdc = kbdc;
76180ee5cbfSDavid du Colombier
76280ee5cbfSDavid du Colombier if(mousec == nil){
76380ee5cbfSDavid du Colombier cs->mousectl = initmouse(nil, im);
76480ee5cbfSDavid du Colombier if(cs->mousectl == nil)
76580ee5cbfSDavid du Colombier ctlerror("can't initialize mouse: %r");
76680ee5cbfSDavid du Colombier mousec = cs->mousectl->c;
76780ee5cbfSDavid du Colombier resizec = cs->mousectl->resizec;
76880ee5cbfSDavid du Colombier }
76980ee5cbfSDavid du Colombier cs->mousec = mousec;
77080ee5cbfSDavid du Colombier cs->resizec = resizec;
771b7b24591SDavid du Colombier cs->ctl = chancreate(sizeof(char*), 64); /* buffer to prevent deadlock */
7729a747e4fSDavid du Colombier cs->data = chancreate(sizeof(char*), 0);
77380ee5cbfSDavid du Colombier cs->resizeexitc = chancreate(sizeof(int), 0);
7749a747e4fSDavid du Colombier cs->csexitc = chancreate(sizeof(int), 0);
77580ee5cbfSDavid du Colombier
7769a747e4fSDavid du Colombier threadcreate(resizethread, cs, 32*1024);
7779a747e4fSDavid du Colombier threadcreate(controlsetthread, cs, 32*1024);
77880ee5cbfSDavid du Colombier
77980ee5cbfSDavid du Colombier controlset = ctlrealloc(controlset, (ncontrolset+1)*sizeof(Controlset*));
78080ee5cbfSDavid du Colombier controlset[ncontrolset++] = cs;
78180ee5cbfSDavid du Colombier return cs;
78280ee5cbfSDavid du Colombier }
78380ee5cbfSDavid du Colombier
78480ee5cbfSDavid du Colombier void
closecontrolset(Controlset * cs)78580ee5cbfSDavid du Colombier closecontrolset(Controlset *cs)
78680ee5cbfSDavid du Colombier {
78780ee5cbfSDavid du Colombier int i;
78880ee5cbfSDavid du Colombier
7899a747e4fSDavid du Colombier sendul(cs->resizeexitc, 0);
7909a747e4fSDavid du Colombier chanfree(cs->resizeexitc);
7919a747e4fSDavid du Colombier sendul(cs->csexitc, 0);
7929a747e4fSDavid du Colombier chanfree(cs->csexitc);
7939a747e4fSDavid du Colombier chanfree(cs->ctl);
7949a747e4fSDavid du Colombier chanfree(cs->data);
7959a747e4fSDavid du Colombier
79680ee5cbfSDavid du Colombier for(i=0; i<ncontrolset; i++)
79780ee5cbfSDavid du Colombier if(cs == controlset[i]){
79880ee5cbfSDavid du Colombier memmove(controlset+i, controlset+i+1, (ncontrolset-(i+1))*sizeof(Controlset*));
79980ee5cbfSDavid du Colombier ncontrolset--;
80080ee5cbfSDavid du Colombier goto Found;
80180ee5cbfSDavid du Colombier }
80280ee5cbfSDavid du Colombier
80380ee5cbfSDavid du Colombier if(i == ncontrolset)
80480ee5cbfSDavid du Colombier ctlerror("closecontrolset: control set not found");
80580ee5cbfSDavid du Colombier
80680ee5cbfSDavid du Colombier Found:
80780ee5cbfSDavid du Colombier while(cs->controls != nil)
80880ee5cbfSDavid du Colombier closecontrol(cs->controls);
80980ee5cbfSDavid du Colombier }
810