20 static Controlset **controlset;
24 char *alignnames[Nalignments] = {
25 [Aupperleft] = "upperleft",
26 [Auppercenter] = "uppercenter",
27 [Aupperright] = "upperright",
28 [Acenterleft] = "centerleft",
30 [Acenterright] = "centerright",
31 [Alowerleft] = "lowerleft",
32 [Alowercenter] = "lowercenter",
33 [Alowerright] = "lowerright",
36 char *ctltypenames[Ntypes] = {
37 [Ctlunknown] = "unknown",
39 [Ctlbutton] = "button",
41 [Ctlkeyboard] = "keyboard",
45 [Ctlscribble] = "scribble",
46 [Ctlslider] = "slider",
49 [Ctltextbutton] = "textbutton",
50 [Ctltextbutton3] = "textbutton3",
51 [Ctlgroup] = "group", // divider between controls and metacontrols
52 [Ctlboxbox] = "boxbox",
53 [Ctlcolumn] = "column",
59 static void _ctlcmd(Controlset*, char*);
60 static void _ctlcontrol(Controlset*, char*);
63 _mkctlcmd(Control *c, char *fmt, va_list arg)
65 char *name, *p, *both;
67 name = quotestrdup(c->name);
69 ctlerror("quotestrdup in ctlprint failed");
70 p = vsmprint(fmt, arg);
73 ctlerror("vsmprint1 in ctlprint failed");
75 both = ctlmalloc(strlen(name)+strlen(p)+2);
85 ctlprint(Control *c, char *fmt, ...)
92 p = _mkctlcmd(c, fmt, arg);
94 n = sendp(c->controlset->ctl, p);
100 _ctlprint(Control *c, char *fmt, ...)
106 p = _mkctlcmd(c, fmt, arg);
108 _ctlcmd(c->controlset, p);
113 _ctllookup(char *s, char *tab[], int ntab)
117 for(i=0; i<ntab; i++)
118 if(tab[i] != nil && strcmp(s, tab[i]) == 0)
124 _newcontrol(Controlset *cs, uint n, char *name, char *type)
128 for(c=cs->controls; c; c=c->next)
129 if(strcmp(c->name, name) == 0){
130 werrstr("control %q already defined", name);
134 c->screen = cs->screen;
135 c->name = ctlstrdup(name);
136 c->type = _ctllookup(type, ctltypenames, Ntypes);
138 ctlerror("unknown type: %s", type);
139 c->event = chancreate(sizeof(char*), 64);
140 c->data = chancreate(sizeof(char*), 0);
141 c->size = Rect(1, 1, _Ctlmaxsize, _Ctlmaxsize);
150 c->next = cs->controls;
156 controlsetthread(void *v)
164 Rune buf[2][20], *rp;
167 snprint(tmp, sizeof tmp, "controlsetthread 0x%p", cs);
170 alts[AKey].c = cs->kbdc;
172 alts[AKey].op = CHANRCV;
173 alts[AMouse].c = cs->mousec;
174 alts[AMouse].v = &mouse;
175 alts[AMouse].op = CHANRCV;
176 alts[ACtl].c = cs->ctl;
178 alts[ACtl].op = CHANRCV;
179 alts[AExit].c = cs->csexitc;
181 alts[AExit].op = CHANRCV;
182 alts[NALT].op = CHANEND;
188 /* toggle so we can receive in one buffer while client processes the other */
189 alts[AKey].v = buf[n];
194 if(ctldeletequits && rp[0]=='\177')
196 for(i=1; i<nelem(buf[0])-1; i++)
197 if(nbrecv(cs->kbdc, rp+i) <= 0)
200 if(cs->focus && cs->focus->key)
201 cs->focus->key(cs->focus, rp);
204 /* is this a focus change? */
205 if(prevbut) /* don't change focus if button was down */
207 if(cs->focus!=nil && cs->focus->hidden == 0 && ptinrect(mouse.xy, cs->focus->rect))
209 if(cs->clicktotype == 0)
211 /* click to type: only change if button is down */
212 if(mouse.buttons == 0)
215 /* change of focus */
217 _ctlprint(cs->focus, "focus 0");
219 for(f=cs->actives; f!=nil; f=f->nextactive)
220 if(f->hidden == 0 && f->mouse && ptinrect(mouse.xy, f->rect)){
222 _ctlprint(f, "focus 1");
224 if (debug) fprint(2, "f->mouse %s\n", f->name);
230 if(cs->focus && cs->focus->mouse) {
231 if (debug) fprint(2, "cs->focus->mouse %s\n", cs->focus->name);
232 cs->focus->mouse(cs->focus, &mouse);
234 prevbut=mouse.buttons;
237 _ctlcontrol(cs, str);
247 _createctl(Controlset *cs, char *type, uint size, char *name)
251 c = _newcontrol(cs, size, name, type);
253 ctlerror("can't create %s control %q: %r", type, name);
258 closecontrol(Control *c)
264 if (c == c->controlset->focus)
265 c->controlset->focus = nil;
270 for(p=c->controlset->controls; p; p=p->next){
276 ctlerror("closecontrol: no such control %q %p\n", c->name, c);
278 c->controlset->controls = c->next;
280 prev->next = c->next;
282 /* is it active? if so, delete from active list */
284 for(p=c->controlset->actives; p; p=p->nextactive){
291 c->controlset->actives = c->nextactive;
293 prev->nextactive = c->nextactive;
306 controlcalled(char *name)
311 for(i=0; i<ncontrolset; i++)
312 for(c=controlset[i]->controls; c; c=c->next)
313 if(strcmp(c->name, name) == 0)
319 ctlerror(char *fmt, ...)
325 vfprint(2, fmt, arg);
336 ret = r = ctlmalloc((utflen(s)+1)*sizeof(Rune));
338 s += chartorune(r++, s);
347 s = ctlmalloc(runestrlen(r)*UTFmax+1);
359 ctlerror("control allocation failed: %r");
364 ctlrealloc(void *p, uint n)
368 ctlerror("control reallocation failed: %r");
379 ctlerror("control strdup(%q) failed: %r", s);
384 ctokenize(char *s, CParse *cp)
386 snprint(cp->str, sizeof cp->str, "%s", s);
387 cp->args = cp->pargs;
388 cp->nargs = tokenize(s, cp->args, nelem(cp->pargs));
392 ctlparse(CParse *cp, char *s, int hasreceiver)
397 /* keep original string for good error messages */
398 strncpy(cp->str, s, sizeof cp->str);
399 cp->str[sizeof cp->str - 1] = '\0';
403 /* strip leading sender name if present */
405 i = strlen(cp->args[0])-1;
406 if(cp->args[0][i] == ':'){
407 cp->sender = cp->args[0];
408 cp->sender[i] = '\0';
415 cp->receiver = *cp->args++;
418 for(i=0; i<cp->nargs; i++){
420 while(*t == '[') /* %R gives [0 0] [1 1]; atoi will stop at closing ] */
422 cp->iargs[i] = atoi(t);
428 _ctlargcount(Control *c, CParse *cp, int n)
431 ctlerror("%q: wrong argument count in '%s'", c->name, cp->str);
435 _ctlcmd(Controlset *cs, char*s)
439 int ircvrs[32], n, i, hit;
442 // fprint(2, "_ctlcmd: %s\n", s);
444 if (ctlparse(&cp, s, 1) < 0)
445 ctlerror("bad command string: %q", cp.str);
446 if (cp.nargs == 0 && strcmp(cp.receiver, "sync") == 0){
447 chanprint(cs->data, "sync");
451 ctlerror("no command in command string: %q", cp.str);
453 n = tokenize(cp.receiver, rcvrs, nelem(rcvrs));
455 // lookup type names: a receiver can be a named type or a named control
456 for (i = 0; i < n; i++)
457 ircvrs[i] = _ctllookup(rcvrs[i], ctltypenames, Ntypes);
459 for(c = cs->controls; c != nil; c = c->next){
460 /* if a control matches on more than one receiver element,
461 * make sure it gets processed once; hence loop through controls
465 for (i = 0; i < n; i++)
466 if(strcmp(c->name, rcvrs[i]) == 0 || c->type == ircvrs[i])
474 _ctlcontrol(Controlset *cs, char *s)
480 // fprint(2, "_ctlcontrol: %s\n", s);
481 n = gettokens(s, lines, nelem(lines), "\n");
484 while(*l==' ' || *l=='\t')
502 seek(_ctlsnarffd, 0, 0);
503 while((n = read(_ctlsnarffd, buf, sizeof buf)) > 0){
504 sn = ctlrealloc(sn, i+n+1);
505 memmove(sn+i, buf, n);
511 snarf = _ctlrunestr(sn);
518 _ctlputsnarf(Rune *snarf)
520 int fd, i, n, nsnarf;
522 if(_ctlsnarffd<0 || snarf[0]==0)
524 fd = open("/dev/snarf", OWRITE);
527 nsnarf = runestrlen(snarf);
528 /* snarf buffer could be huge, so fprint will truncate; do it in blocks */
529 for(i=0; i<nsnarf; i+=n){
533 if(fprint(fd, "%.*S", n, snarf+i) < 0)
540 _ctlalignment(char *s)
544 i = _ctllookup(s, alignnames, Nalignments);
546 ctlerror("unknown alignment: %s", s);
551 _ctlalignpoint(Rectangle r, int dx, int dy, int align)
555 p = r.min; /* in case of trouble */
561 p.x = r.min.x+(Dx(r)-dx)/2;
572 p.y = r.min.y+(Dy(r)-dy)/2;
582 controlwire(Control *cfrom, char *name, Channel *chan)
587 if(strcmp(name, "event") == 0){
590 }else if(strcmp(name, "data") == 0){
594 ctlerror("%q: unknown controlwire channel %s", cfrom->name, name);
600 _ctlfocus(Control *me, int set)
609 _ctlprint(cs->focus, "focus 0");
619 resizethread(void *v)
626 snprint(buf, sizeof buf, "resizethread0x%p", cs);
629 alts[0].c = cs->resizec;
631 alts[0].op = CHANRCV;
632 alts[1].c = cs->resizeexitc;
634 alts[1].op = CHANRCV;
635 alts[2].op = CHANEND;
640 resizecontrolset(cs);
653 for(c=a->controlset->actives; c; c=c->nextactive)
655 ctlerror("%q already active\n", a->name);
662 a->nextactive = a->controlset->actives;
663 a->controlset->actives = a;
667 deactivate(Control *a)
671 /* if group, first deactivate kids, then self */
677 for(c=a->controlset->actives; c; c=c->nextactive){
679 if(a->controlset->focus == a)
680 a->controlset->focus = nil;
682 prev->nextactive = a->nextactive;
684 a->controlset->actives = a->nextactive;
689 ctlerror("%q not active\n", a->name);
703 "paleyellow", DPaleyellow,
704 "darkyellow", DDarkyellow,
705 "darkgreen", DDarkgreen,
706 "palegreen", DPalegreen,
707 "medgreen", DMedgreen,
708 "darkblue", DDarkblue,
709 "palebluegreen", DPalebluegreen,
710 "paleblue", DPaleblue,
711 "bluegreen", DBluegreen,
712 "greygreen", DGreygreen,
713 "palegreygreen", DPalegreygreen,
714 "yellowgreen", DYellowgreen,
716 "greyblue", DGreyblue,
717 "palegreyblue", DPalegreyblue,
718 "purpleblue", DPurpleblue,
729 namectlimage(display->opaque, "opaque");
730 namectlimage(display->transparent, "transparent");
731 namectlimage(display->white, "white");
732 namectlimage(display->black, "black");
733 for(i=0; coltab[i].name!=nil; i++){
734 im = allocimage(display, Rect(0,0,1,1), RGB24, 1, coltab[i].color);
735 namectlimage(im, coltab[i].name);
737 namectlfont(font, "font");
738 _ctlsnarffd = open("/dev/snarf", OREAD);
742 newcontrolset(Image *im, Channel *kbdc, Channel *mousec, Channel *resizec)
748 if((mousec==nil && resizec!=nil) || (mousec!=nil && resizec==nil))
749 ctlerror("must specify either or both of mouse and resize channels");
751 cs = ctlmalloc(sizeof(Controlset));
755 cs->keyboardctl = initkeyboard(nil);
756 if(cs->keyboardctl == nil)
757 ctlerror("can't initialize keyboard: %r");
758 kbdc = cs->keyboardctl->c;
763 cs->mousectl = initmouse(nil, im);
764 if(cs->mousectl == nil)
765 ctlerror("can't initialize mouse: %r");
766 mousec = cs->mousectl->c;
767 resizec = cs->mousectl->resizec;
770 cs->resizec = resizec;
771 cs->ctl = chancreate(sizeof(char*), 64); /* buffer to prevent deadlock */
772 cs->data = chancreate(sizeof(char*), 0);
773 cs->resizeexitc = chancreate(sizeof(int), 0);
774 cs->csexitc = chancreate(sizeof(int), 0);
776 threadcreate(resizethread, cs, 32*1024);
777 threadcreate(controlsetthread, cs, 32*1024);
779 controlset = ctlrealloc(controlset, (ncontrolset+1)*sizeof(Controlset*));
780 controlset[ncontrolset++] = cs;
785 closecontrolset(Controlset *cs)
789 sendul(cs->resizeexitc, 0);
790 chanfree(cs->resizeexitc);
791 sendul(cs->csexitc, 0);
792 chanfree(cs->csexitc);
796 for(i=0; i<ncontrolset; i++)
797 if(cs == controlset[i]){
798 memmove(controlset+i, controlset+i+1, (ncontrolset-(i+1))*sizeof(Controlset*));
804 ctlerror("closecontrolset: control set not found");
807 while(cs->controls != nil)
808 closecontrol(cs->controls);