/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <draw.h>#include <thread.h>#include <mouse.h>#include <keyboard.h>#include <control.h> static int debug = 0; enum /* alts */{ AKey, AMouse, ACtl, AExit, NALT}; static Controlset **controlset;int ncontrolset;int ctldeletequits; char *alignnames[Nalignments] = { [Aupperleft] = "upperleft", [Auppercenter] = "uppercenter", [Aupperright] = "upperright", [Acenterleft] = "centerleft", [Acenter] = "center", [Acenterright] = "centerright", [Alowerleft] = "lowerleft", [Alowercenter] = "lowercenter", [Alowerright] = "lowerright",}; char *ctltypenames[Ntypes] = { [Ctlunknown] = "unknown", [Ctlbox] = "box", [Ctlbutton] = "button", [Ctlentry] = "entry", [Ctlkeyboard] = "keyboard", [Ctllabel] = "label", [Ctlmenu] = "menu", [Ctlradio] = "radio", [Ctlscribble] = "scribble", [Ctlslider] = "slider", [Ctltabs] = "tabs", [Ctltext] = "text", [Ctltextbutton] = "textbutton", [Ctltextbutton3] = "textbutton3", [Ctlgroup] = "group", // divider between controls and metacontrols [Ctlboxbox] = "boxbox", [Ctlcolumn] = "column", [Ctlrow] = "row", [Ctlstack] = "stack", [Ctltab] = "tab",}; static void _ctlcmd(Controlset*, char*);static void _ctlcontrol(Controlset*, char*); static char*_mkctlcmd(Control *c, char *fmt, va_list arg){ char *name, *p, *both; name = quotestrdup(c->name); if(name == nil) ctlerror("quotestrdup in ctlprint failed"); p = vsmprint(fmt, arg); if(p == nil){ free(name); ctlerror("vsmprint1 in ctlprint failed"); } both = ctlmalloc(strlen(name)+strlen(p)+2); strcpy(both, name); strcat(both, " "); strcat(both, p); free(name); free(p); return both;} intctlprint(Control *c, char *fmt, ...){ int n; char *p; va_list arg; va_start(arg, fmt); p = _mkctlcmd(c, fmt, arg); va_end(arg); n = sendp(c->controlset->ctl, p); yield(); return n;} void_ctlprint(Control *c, char *fmt, ...){ char *p; va_list arg; va_start(arg, fmt); p = _mkctlcmd(c, fmt, arg); va_end(arg); _ctlcmd(c->controlset, p); free(p);} int_ctllookup(char *s, char *tab[], int ntab){ int i; for(i=0; i<ntab; i++) if(tab[i] != nil && strcmp(s, tab[i]) == 0) return i; return -1;} static Control*_newcontrol(Controlset *cs, uint n, char *name, char *type){ Control *c; for(c=cs->controls; c; c=c->next) if(strcmp(c->name, name) == 0){ werrstr("control %q already defined", name); return nil; } c = ctlmalloc(n); c->screen = cs->screen; c->name = ctlstrdup(name); c->type = _ctllookup(type, ctltypenames, Ntypes); if (c->type < 0) ctlerror("unknown type: %s", type); c->event = chancreate(sizeof(char*), 64); c->data = chancreate(sizeof(char*), 0); c->size = Rect(1, 1, _Ctlmaxsize, _Ctlmaxsize); c->hidden = 0; c->ctl = nil; c->mouse = nil; c->key = nil; c->exit = nil; c->setsize = nil; c->controlset = cs; c->next = cs->controls; cs->controls = c; return c;} static voidcontrolsetthread(void *v){ Controlset *cs; Mouse mouse; Control *f; int prevbut, n, i; Alt alts[NALT+1]; char tmp[64], *str; Rune buf[2][20], *rp; cs = v; snprint(tmp, sizeof tmp, "controlsetthread 0x%p", cs); threadsetname(tmp); alts[AKey].c = cs->kbdc; alts[AKey].v = &rp; alts[AKey].op = CHANRCV; alts[AMouse].c = cs->mousec; alts[AMouse].v = &mouse; alts[AMouse].op = CHANRCV; alts[ACtl].c = cs->ctl; alts[ACtl].v = &str; alts[ACtl].op = CHANRCV; alts[AExit].c = cs->csexitc; alts[AExit].v = nil; alts[AExit].op = CHANRCV; alts[NALT].op = CHANEND; cs->focus = nil; prevbut=0; n = 0; for(;;){ /* toggle so we can receive in one buffer while client processes the other */ alts[AKey].v = buf[n]; rp = buf[n]; n = 1-n; switch(alt(alts)){ case AKey: if(ctldeletequits && rp[0]=='\177') ctlerror("delete"); for(i=1; i<nelem(buf[0])-1; i++) if(nbrecv(cs->kbdc, rp+i) <= 0) break; rp[i] = L'\0'; if(cs->focus && cs->focus->key) cs->focus->key(cs->focus, rp); break; case AMouse: /* is this a focus change? */ if(prevbut) /* don't change focus if button was down */ goto Send; if(cs->focus!=nil && cs->focus->hidden == 0 && ptinrect(mouse.xy, cs->focus->rect)) goto Send; if(cs->clicktotype == 0) goto Change; /* click to type: only change if button is down */ if(mouse.buttons == 0) goto Send; Change: /* change of focus */ if(cs->focus != nil) _ctlprint(cs->focus, "focus 0"); cs->focus = nil; for(f=cs->actives; f!=nil; f=f->nextactive) if(f->hidden == 0 && f->mouse && ptinrect(mouse.xy, f->rect)){ cs->focus = f; _ctlprint(f, "focus 1"); if (f->mouse) { if (debug) fprint(2, "f->mouse %s\n", f->name); f->mouse(f, &mouse); } break; } Send: if(cs->focus && cs->focus->mouse) { if (debug) fprint(2, "cs->focus->mouse %s\n", cs->focus->name); cs->focus->mouse(cs->focus, &mouse); } prevbut=mouse.buttons; break; case ACtl: _ctlcontrol(cs, str); free(str); break; case AExit: threadexits(nil); } }} Control*_createctl(Controlset *cs, char *type, uint size, char *name){ Control *c; c = _newcontrol(cs, size, name, type); if(c == nil) ctlerror("can't create %s control %q: %r", type, name); return c;} voidclosecontrol(Control *c){ Control *prev, *p; if(c == nil) return; if (c == c->controlset->focus) c->controlset->focus = nil; if(c->exit) c->exit(c); prev = nil; for(p=c->controlset->controls; p; p=p->next){ if(p == c) break; prev = p; } if(p == nil) ctlerror("closecontrol: no such control %q %p\n", c->name, c); if(prev == nil) c->controlset->controls = c->next; else prev->next = c->next; /* is it active? if so, delete from active list */ prev = nil; for(p=c->controlset->actives; p; p=p->nextactive){ if(p == c) break; prev = p; } if(p != nil){ if(prev == nil) c->controlset->actives = c->nextactive; else prev->nextactive = c->nextactive; } if(!c->wevent) chanfree(c->event); if(!c->wdata) chanfree(c->data); free(c->name); free(c->format); free(c);} Control*controlcalled(char *name){ Control *c; int i; for(i=0; i<ncontrolset; i++) for(c=controlset[i]->controls; c; c=c->next) if(strcmp(c->name, name) == 0) return c; return nil;} voidctlerror(char *fmt, ...){ va_list arg; char buf[256]; va_start(arg, fmt); vfprint(2, fmt, arg); va_end(arg); write(2, "\n", 1); threadexitsall(buf);} Rune*_ctlrunestr(char *s){ Rune *r, *ret; ret = r = ctlmalloc((utflen(s)+1)*sizeof(Rune)); while(*s != '\0') s += chartorune(r++, s); *r = L'\0'; return ret;} char*_ctlstrrune(Rune *r){ char *s; s = ctlmalloc(runestrlen(r)*UTFmax+1); sprint(s, "%S", r); return s;} void*ctlmalloc(uint n){ void *p; p = mallocz(n, 1); if(p == nil) ctlerror("control allocation failed: %r"); return p;} void*ctlrealloc(void *p, uint n){ p = realloc(p, n); if(p == nil) ctlerror("control reallocation failed: %r"); return p;} char*ctlstrdup(char *s){ char *t; t = strdup(s); if(t == nil) ctlerror("control strdup(%q) failed: %r", s); return t;} static voidctokenize(char *s, CParse *cp){ snprint(cp->str, sizeof cp->str, "%s", s); cp->args = cp->pargs; cp->nargs = tokenize(s, cp->args, nelem(cp->pargs));} static intctlparse(CParse *cp, char *s, int hasreceiver){ int i; char *t; /* keep original string for good error messages */ strncpy(cp->str, s, sizeof cp->str); cp->str[sizeof cp->str - 1] = '\0'; ctokenize(s, cp); if(cp->nargs == 0) return -1; /* strip leading sender name if present */ cp->sender = nil; i = strlen(cp->args[0])-1; if(cp->args[0][i] == ':'){ cp->sender = cp->args[0]; cp->sender[i] = '\0'; cp->args++; cp->nargs--; } if(hasreceiver){ if(cp->nargs-- == 0) return -1; cp->receiver = *cp->args++; }else cp->receiver = nil; for(i=0; i<cp->nargs; i++){ t = cp->args[i]; while(*t == '[') /* %R gives [0 0] [1 1]; atoi will stop at closing ] */ t++; cp->iargs[i] = atoi(t); } return cp->nargs;} void_ctlargcount(Control *c, CParse *cp, int n){ if(cp->nargs != n) ctlerror("%q: wrong argument count in '%s'", c->name, cp->str);} static void_ctlcmd(Controlset *cs, char*s){ CParse cp; char *rcvrs[32]; int ircvrs[32], n, i, hit; Control *c; // fprint(2, "_ctlcmd: %s\n", s); cp.args = cp.pargs; if (ctlparse(&cp, s, 1) < 0) ctlerror("bad command string: %q", cp.str); if (cp.nargs == 0 && strcmp(cp.receiver, "sync") == 0){ chanprint(cs->data, "sync"); return; } if (cp.nargs == 0) ctlerror("no command in command string: %q", cp.str); n = tokenize(cp.receiver, rcvrs, nelem(rcvrs)); // lookup type names: a receiver can be a named type or a named control for (i = 0; i < n; i++) ircvrs[i] = _ctllookup(rcvrs[i], ctltypenames, Ntypes); for(c = cs->controls; c != nil; c = c->next){ /* if a control matches on more than one receiver element, * make sure it gets processed once; hence loop through controls * in the outer loop */ hit = 0; for (i = 0; i < n; i++) if(strcmp(c->name, rcvrs[i]) == 0 || c->type == ircvrs[i]) hit++; if (hit && c->ctl) c->ctl(c, &cp); }} static void_ctlcontrol(Controlset *cs, char *s){ char *lines[16]; int i, n; char *l; // fprint(2, "_ctlcontrol: %s\n", s); n = gettokens(s, lines, nelem(lines), "\n"); for(i=0; i<n; i++){ l = lines[i]; while(*l==' ' || *l=='\t') l++; if(*l != '\0') _ctlcmd(cs, l); }} Rune*Lines 1–500 of 818. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h> #include <libc.h> #include <draw.h> #include <thread.h> #include <mouse.h> #include <keyboard.h> #include <control.h> static int debug = 0; enum /* alts */ { AKey, AMouse, ACtl, AExit, NALT }; static Controlset **controlset; int ncontrolset; int ctldeletequits; char *alignnames[Nalignments] = { [Aupperleft] = "upperleft", [Auppercenter] = "uppercenter", [Aupperright] = "upperright", [Acenterleft] = "centerleft", [Acenter] = "center", [Acenterright] = "centerright", [Alowerleft] = "lowerleft", [Alowercenter] = "lowercenter", [Alowerright] = "lowerright", }; char *ctltypenames[Ntypes] = { [Ctlunknown] = "unknown", [Ctlbox] = "box", [Ctlbutton] = "button", [Ctlentry] = "entry", [Ctlkeyboard] = "keyboard", [Ctllabel] = "label", [Ctlmenu] = "menu", [Ctlradio] = "radio", [Ctlscribble] = "scribble", [Ctlslider] = "slider", [Ctltabs] = "tabs", [Ctltext] = "text", [Ctltextbutton] = "textbutton", [Ctltextbutton3] = "textbutton3", [Ctlgroup] = "group", // divider between controls and metacontrols [Ctlboxbox] = "boxbox", [Ctlcolumn] = "column", [Ctlrow] = "row", [Ctlstack] = "stack", [Ctltab] = "tab", }; static void _ctlcmd(Controlset*, char*); static void _ctlcontrol(Controlset*, char*); static char* _mkctlcmd(Control *c, char *fmt, va_list arg) { char *name, *p, *both; name = quotestrdup(c->name); if(name == nil) ctlerror("quotestrdup in ctlprint failed"); p = vsmprint(fmt, arg); if(p == nil){ free(name); ctlerror("vsmprint1 in ctlprint failed"); } both = ctlmalloc(strlen(name)+strlen(p)+2); strcpy(both, name); strcat(both, " "); strcat(both, p); free(name); free(p); return both; } int ctlprint(Control *c, char *fmt, ...) { int n; char *p; va_list arg; va_start(arg, fmt); p = _mkctlcmd(c, fmt, arg); va_end(arg); n = sendp(c->controlset->ctl, p); yield(); return n; } void _ctlprint(Control *c, char *fmt, ...) { char *p; va_list arg; va_start(arg, fmt); p = _mkctlcmd(c, fmt, arg); va_end(arg); _ctlcmd(c->controlset, p); free(p); } int _ctllookup(char *s, char *tab[], int ntab) { int i; for(i=0; i<ntab; i++) if(tab[i] != nil && strcmp(s, tab[i]) == 0) return i; return -1; } static Control* _newcontrol(Controlset *cs, uint n, char *name, char *type) { Control *c; for(c=cs->controls; c; c=c->next) if(strcmp(c->name, name) == 0){ werrstr("control %q already defined", name); return nil; } c = ctlmalloc(n); c->screen = cs->screen; c->name = ctlstrdup(name); c->type = _ctllookup(type, ctltypenames, Ntypes); if (c->type < 0) ctlerror("unknown type: %s", type); c->event = chancreate(sizeof(char*), 64); c->data = chancreate(sizeof(char*), 0); c->size = Rect(1, 1, _Ctlmaxsize, _Ctlmaxsize); c->hidden = 0; c->ctl = nil; c->mouse = nil; c->key = nil; c->exit = nil; c->setsize = nil; c->controlset = cs; c->next = cs->controls; cs->controls = c; return c; } static void controlsetthread(void *v) { Controlset *cs; Mouse mouse; Control *f; int prevbut, n, i; Alt alts[NALT+1]; char tmp[64], *str; Rune buf[2][20], *rp; cs = v; snprint(tmp, sizeof tmp, "controlsetthread 0x%p", cs); threadsetname(tmp); alts[AKey].c = cs->kbdc; alts[AKey].v = &rp; alts[AKey].op = CHANRCV; alts[AMouse].c = cs->mousec; alts[AMouse].v = &mouse; alts[AMouse].op = CHANRCV; alts[ACtl].c = cs->ctl; alts[ACtl].v = &str; alts[ACtl].op = CHANRCV; alts[AExit].c = cs->csexitc; alts[AExit].v = nil; alts[AExit].op = CHANRCV; alts[NALT].op = CHANEND; cs->focus = nil; prevbut=0; n = 0; for(;;){ /* toggle so we can receive in one buffer while client processes the other */ alts[AKey].v = buf[n]; rp = buf[n]; n = 1-n; switch(alt(alts)){ case AKey: if(ctldeletequits && rp[0]=='\177') ctlerror("delete"); for(i=1; i<nelem(buf[0])-1; i++) if(nbrecv(cs->kbdc, rp+i) <= 0) break; rp[i] = L'\0'; if(cs->focus && cs->focus->key) cs->focus->key(cs->focus, rp); break; case AMouse: /* is this a focus change? */ if(prevbut) /* don't change focus if button was down */ goto Send; if(cs->focus!=nil && cs->focus->hidden == 0 && ptinrect(mouse.xy, cs->focus->rect)) goto Send; if(cs->clicktotype == 0) goto Change; /* click to type: only change if button is down */ if(mouse.buttons == 0) goto Send; Change: /* change of focus */ if(cs->focus != nil) _ctlprint(cs->focus, "focus 0"); cs->focus = nil; for(f=cs->actives; f!=nil; f=f->nextactive) if(f->hidden == 0 && f->mouse && ptinrect(mouse.xy, f->rect)){ cs->focus = f; _ctlprint(f, "focus 1"); if (f->mouse) { if (debug) fprint(2, "f->mouse %s\n", f->name); f->mouse(f, &mouse); } break; } Send: if(cs->focus && cs->focus->mouse) { if (debug) fprint(2, "cs->focus->mouse %s\n", cs->focus->name); cs->focus->mouse(cs->focus, &mouse); } prevbut=mouse.buttons; break; case ACtl: _ctlcontrol(cs, str); free(str); break; case AExit: threadexits(nil); } } } Control* _createctl(Controlset *cs, char *type, uint size, char *name) { Control *c; c = _newcontrol(cs, size, name, type); if(c == nil) ctlerror("can't create %s control %q: %r", type, name); return c; } void closecontrol(Control *c) { Control *prev, *p; if(c == nil) return; if (c == c->controlset->focus) c->controlset->focus = nil; if(c->exit) c->exit(c); prev = nil; for(p=c->controlset->controls; p; p=p->next){ if(p == c) break; prev = p; } if(p == nil) ctlerror("closecontrol: no such control %q %p\n", c->name, c); if(prev == nil) c->controlset->controls = c->next; else prev->next = c->next; /* is it active? if so, delete from active list */ prev = nil; for(p=c->controlset->actives; p; p=p->nextactive){ if(p == c) break; prev = p; } if(p != nil){ if(prev == nil) c->controlset->actives = c->nextactive; else prev->nextactive = c->nextactive; } if(!c->wevent) chanfree(c->event); if(!c->wdata) chanfree(c->data); free(c->name); free(c->format); free(c); } Control* controlcalled(char *name) { Control *c; int i; for(i=0; i<ncontrolset; i++) for(c=controlset[i]->controls; c; c=c->next) if(strcmp(c->name, name) == 0) return c; return nil; } void ctlerror(char *fmt, ...) { va_list arg; char buf[256]; va_start(arg, fmt); vfprint(2, fmt, arg); va_end(arg); write(2, "\n", 1); threadexitsall(buf); } Rune* _ctlrunestr(char *s) { Rune *r, *ret; ret = r = ctlmalloc((utflen(s)+1)*sizeof(Rune)); while(*s != '\0') s += chartorune(r++, s); *r = L'\0'; return ret; } char* _ctlstrrune(Rune *r) { char *s; s = ctlmalloc(runestrlen(r)*UTFmax+1); sprint(s, "%S", r); return s; } void* ctlmalloc(uint n) { void *p; p = mallocz(n, 1); if(p == nil) ctlerror("control allocation failed: %r"); return p; } void* ctlrealloc(void *p, uint n) { p = realloc(p, n); if(p == nil) ctlerror("control reallocation failed: %r"); return p; } char* ctlstrdup(char *s) { char *t; t = strdup(s); if(t == nil) ctlerror("control strdup(%q) failed: %r", s); return t; } static void ctokenize(char *s, CParse *cp) { snprint(cp->str, sizeof cp->str, "%s", s); cp->args = cp->pargs; cp->nargs = tokenize(s, cp->args, nelem(cp->pargs)); } static int ctlparse(CParse *cp, char *s, int hasreceiver) { int i; char *t; /* keep original string for good error messages */ strncpy(cp->str, s, sizeof cp->str); cp->str[sizeof cp->str - 1] = '\0'; ctokenize(s, cp); if(cp->nargs == 0) return -1; /* strip leading sender name if present */ cp->sender = nil; i = strlen(cp->args[0])-1; if(cp->args[0][i] == ':'){ cp->sender = cp->args[0]; cp->sender[i] = '\0'; cp->args++; cp->nargs--; } if(hasreceiver){ if(cp->nargs-- == 0) return -1; cp->receiver = *cp->args++; }else cp->receiver = nil; for(i=0; i<cp->nargs; i++){ t = cp->args[i]; while(*t == '[') /* %R gives [0 0] [1 1]; atoi will stop at closing ] */ t++; cp->iargs[i] = atoi(t); } return cp->nargs; } void _ctlargcount(Control *c, CParse *cp, int n) { if(cp->nargs != n) ctlerror("%q: wrong argument count in '%s'", c->name, cp->str); } static void _ctlcmd(Controlset *cs, char*s) { CParse cp; char *rcvrs[32]; int ircvrs[32], n, i, hit; Control *c; // fprint(2, "_ctlcmd: %s\n", s); cp.args = cp.pargs; if (ctlparse(&cp, s, 1) < 0) ctlerror("bad command string: %q", cp.str); if (cp.nargs == 0 && strcmp(cp.receiver, "sync") == 0){ chanprint(cs->data, "sync"); return; } if (cp.nargs == 0) ctlerror("no command in command string: %q", cp.str); n = tokenize(cp.receiver, rcvrs, nelem(rcvrs)); // lookup type names: a receiver can be a named type or a named control for (i = 0; i < n; i++) ircvrs[i] = _ctllookup(rcvrs[i], ctltypenames, Ntypes); for(c = cs->controls; c != nil; c = c->next){ /* if a control matches on more than one receiver element, * make sure it gets processed once; hence loop through controls * in the outer loop */ hit = 0; for (i = 0; i < n; i++) if(strcmp(c->name, rcvrs[i]) == 0 || c->type == ircvrs[i]) hit++; if (hit && c->ctl) c->ctl(c, &cp); } } static void _ctlcontrol(Controlset *cs, char *s) { char *lines[16]; int i, n; char *l; // fprint(2, "_ctlcontrol: %s\n", s); n = gettokens(s, lines, nelem(lines), "\n"); for(i=0; i<n; i++){ l = lines[i]; while(*l==' ' || *l=='\t') l++; if(*l != '\0') _ctlcmd(cs, l); } } Rune*