123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- #include <u.h>
- #include <libc.h>
- #include <draw.h>
- #include <thread.h>
- #include <cursor.h>
- #include <mouse.h>
- #include <keyboard.h>
- #include <frame.h>
- #include <fcall.h>
- #include <plumb.h>
- #include "dat.h"
- #include "fns.h"
- #include <ctype.h>
- char Ebadwr[] = "bad rectangle in wctl request";
- char Ewalloc[] = "window allocation failed in wctl request";
- /* >= Top are disallowed if mouse button is pressed */
- enum
- {
- New,
- Resize,
- Move,
- Scroll,
- Noscroll,
- Set,
- Top,
- Bottom,
- Current,
- Hide,
- Unhide,
- Delete,
- };
- static char *cmds[] = {
- [New] = "new",
- [Resize] = "resize",
- [Move] = "move",
- [Scroll] = "scroll",
- [Noscroll] = "noscroll",
- [Set] = "set",
- [Top] = "top",
- [Bottom] = "bottom",
- [Current] = "current",
- [Hide] = "hide",
- [Unhide] = "unhide",
- [Delete] = "delete",
- nil
- };
- enum
- {
- Cd,
- Deltax,
- Deltay,
- Hidden,
- Id,
- Maxx,
- Maxy,
- Minx,
- Miny,
- PID,
- R,
- Scrolling,
- Noscrolling,
- };
- static char *params[] = {
- [Cd] = "-cd",
- [Deltax] = "-dx",
- [Deltay] = "-dy",
- [Hidden] = "-hide",
- [Id] = "-id",
- [Maxx] = "-maxx",
- [Maxy] = "-maxy",
- [Minx] = "-minx",
- [Miny] = "-miny",
- [PID] = "-pid",
- [R] = "-r",
- [Scrolling] = "-scroll",
- [Noscrolling] = "-noscroll",
- nil
- };
- /*
- * Check that newly created window will be of manageable size
- */
- int
- goodrect(Rectangle r)
- {
- if(!eqrect(canonrect(r), r))
- return 0;
- if(Dx(r)<100 || Dy(r)<3*font->height)
- return 0;
- /* must have some screen and border visible so we can move it out of the way */
- if(Dx(r) >= Dx(screen->r) && Dy(r) >= Dy(screen->r))
- return 0;
- /* reasonable sizes only please */
- if(Dx(r) > BIG*Dx(screen->r))
- return 0;
- if(Dy(r) > BIG*Dx(screen->r))
- return 0;
- return 1;
- }
- static
- int
- word(char **sp, char *tab[])
- {
- char *s, *t;
- int i;
- s = *sp;
- while(isspace(*s))
- s++;
- t = s;
- while(*s!='\0' && !isspace(*s))
- s++;
- for(i=0; tab[i]!=nil; i++)
- if(strncmp(tab[i], t, strlen(tab[i])) == 0){
- *sp = s;
- return i;
- }
- return -1;
- }
- int
- set(int sign, int neg, int abs, int pos)
- {
- if(sign < 0)
- return neg;
- if(sign > 0)
- return pos;
- return abs;
- }
- Rectangle
- newrect(void)
- {
- static int i = 0;
- int minx, miny, dx, dy;
- dx = min(600, Dx(screen->r) - 2*Borderwidth);
- dy = min(400, Dy(screen->r) - 2*Borderwidth);
- minx = 32 + 16*i;
- miny = 32 + 16*i;
- i++;
- i %= 10;
- return Rect(minx, miny, minx+dx, miny+dy);
- }
- void
- shift(int *minp, int *maxp, int min, int max)
- {
- if(*minp < min){
- *maxp += min-*minp;
- *minp = min;
- }
- if(*maxp > max){
- *minp += max-*maxp;
- *maxp = max;
- }
- }
- Rectangle
- rectonscreen(Rectangle r)
- {
- shift(&r.min.x, &r.max.x, screen->r.min.x, screen->r.max.x);
- shift(&r.min.y, &r.max.y, screen->r.min.y, screen->r.max.y);
- return r;
- }
- /* permit square brackets, in the manner of %R */
- int
- riostrtol(char *s, char **t)
- {
- int n;
- while(*s!='\0' && (*s==' ' || *s=='\t' || *s=='['))
- s++;
- if(*s == '[')
- s++;
- n = strtol(s, t, 10);
- if(*t != s)
- while((*t)[0] == ']')
- (*t)++;
- return n;
- }
- int
- parsewctl(char **argp, Rectangle r, Rectangle *rp, int *pidp, int *idp, int *hiddenp, int *scrollingp, char **cdp, char *s, char *err)
- {
- int cmd, param, xy, sign;
- char *t;
- *pidp = 0;
- *hiddenp = 0;
- *scrollingp = scrolling;
- *cdp = nil;
- cmd = word(&s, cmds);
- if(cmd < 0){
- strcpy(err, "unrecognized wctl command");
- return -1;
- }
- if(cmd == New)
- r = newrect();
- strcpy(err, "missing or bad wctl parameter");
- while((param = word(&s, params)) >= 0){
- switch(param){ /* special cases */
- case Hidden:
- *hiddenp = 1;
- continue;
- case Scrolling:
- *scrollingp = 1;
- continue;
- case Noscrolling:
- *scrollingp = 0;
- continue;
- case R:
- r.min.x = riostrtol(s, &t);
- if(t == s)
- return -1;
- s = t;
- r.min.y = riostrtol(s, &t);
- if(t == s)
- return -1;
- s = t;
- r.max.x = riostrtol(s, &t);
- if(t == s)
- return -1;
- s = t;
- r.max.y = riostrtol(s, &t);
- if(t == s)
- return -1;
- s = t;
- continue;
- }
- while(isspace(*s))
- s++;
- if(param == Cd){
- *cdp = s;
- while(*s && !isspace(*s))
- s++;
- if(*s != '\0')
- *s++ = '\0';
- continue;
- }
- sign = 0;
- if(*s == '-'){
- sign = -1;
- s++;
- }else if(*s == '+'){
- sign = +1;
- s++;
- }
- if(!isdigit(*s))
- return -1;
- xy = riostrtol(s, &s);
- switch(param){
- case -1:
- strcpy(err, "unrecognized wctl parameter");
- return -1;
- case Minx:
- r.min.x = set(sign, r.min.x-xy, xy, r.min.x+xy);
- break;
- case Miny:
- r.min.y = set(sign, r.min.y-xy, xy, r.min.y+xy);
- break;
- case Maxx:
- r.max.x = set(sign, r.max.x-xy, xy, r.max.x+xy);
- break;
- case Maxy:
- r.max.y = set(sign, r.max.y-xy, xy, r.max.y+xy);
- break;
- case Deltax:
- r.max.x = set(sign, r.max.x-xy, r.min.x+xy, r.max.x+xy);
- break;
- case Deltay:
- r.max.y = set(sign, r.max.y-xy, r.min.y+xy, r.max.y+xy);
- break;
- case Id:
- if(idp != nil)
- *idp = xy;
- break;
- case PID:
- if(pidp != nil)
- *pidp = xy;
- break;
- }
- }
- *rp = rectonscreen(rectaddpt(r, screen->r.min));
- while(isspace(*s))
- s++;
- if(cmd!=New && *s!='\0'){
- strcpy(err, "extraneous text in wctl message");
- return -1;
- }
- if(argp)
- *argp = s;
- return cmd;
- }
- int
- wctlnew(Rectangle rect, char *arg, int pid, int hideit, int scrollit, char *dir, char *err)
- {
- char **argv;
- Image *i;
- if(!goodrect(rect)){
- strcpy(err, Ebadwr);
- return -1;
- }
- argv = emalloc(4*sizeof(char*));
- argv[0] = "rc";
- argv[1] = "-c";
- while(isspace(*arg))
- arg++;
- if(*arg == '\0'){
- argv[1] = "-i";
- argv[2] = nil;
- }else{
- argv[2] = arg;
- argv[3] = nil;
- }
- if(hideit)
- i = allocimage(display, rect, screen->chan, 0, DWhite);
- else
- i = allocwindow(wscreen, rect, Refbackup, DWhite);
- if(i == nil){
- strcpy(err, Ewalloc);
- return -1;
- }
- border(i, rect, Selborder, red, ZP);
- new(i, hideit, scrollit, pid, dir, "/bin/rc", argv);
- free(argv); /* when new() returns, argv and args have been copied */
- return 1;
- }
- int
- writewctl(Xfid *x, char *err)
- {
- int cnt, cmd, j, id, hideit, scrollit, pid;
- Image *i;
- char *arg, *dir;
- Rectangle rect;
- Window *w;
- w = x->f->w;
- cnt = x->count;
- x->data[cnt] = '\0';
- id = 0;
- rect = rectsubpt(w->screenr, screen->r.min);
- cmd = parsewctl(&arg, rect, &rect, &pid, &id, &hideit, &scrollit, &dir, x->data, err);
- if(cmd < 0)
- return -1;
- if(mouse->buttons!=0 && cmd>=Top){
- strcpy(err, "action disallowed when mouse active");
- return -1;
- }
- if(id != 0){
- for(j=0; j<nwindow; j++)
- if(window[j]->id == id)
- break;
- if(j == nwindow){
- strcpy(err, "no such window id");
- return -1;
- }
- w = window[j];
- if(w->deleted || w->i==nil){
- strcpy(err, "window deleted");
- return -1;
- }
- }
- switch(cmd){
- case New:
- return wctlnew(rect, arg, pid, hideit, scrollit, dir, err);
- case Set:
- if(pid > 0)
- wsetpid(w, pid, 0);
- return 1;
- case Move:
- rect = Rect(rect.min.x, rect.min.y, rect.min.x+Dx(w->screenr), rect.min.y+Dy(w->screenr));
- rect = rectonscreen(rect);
- /* fall through */
- case Resize:
- if(!goodrect(rect)){
- strcpy(err, Ebadwr);
- return -1;
- }
- if(eqrect(rect, w->screenr))
- return 1;
- i = allocwindow(wscreen, rect, Refbackup, DWhite);
- if(i == nil){
- strcpy(err, Ewalloc);
- return -1;
- }
- border(i, rect, Selborder, red, ZP);
- wsendctlmesg(w, Reshaped, i->r, i);
- return 1;
- case Scroll:
- w->scrolling = 1;
- wshow(w, w->nr);
- wsendctlmesg(w, Wakeup, ZR, nil);
- return 1;
- case Noscroll:
- w->scrolling = 0;
- wsendctlmesg(w, Wakeup, ZR, nil);
- return 1;
- case Top:
- wtopme(w);
- return 1;
- case Bottom:
- wbottomme(w);
- return 1;
- case Current:
- wcurrent(w);
- return 1;
- case Hide:
- switch(whide(w)){
- case -1:
- strcpy(err, "window already hidden");
- return -1;
- case 0:
- strcpy(err, "hide failed");
- return -1;
- default:
- break;
- }
- return 1;
- case Unhide:
- for(j=0; j<nhidden; j++)
- if(hidden[j] == w)
- break;
- if(j == nhidden){
- strcpy(err, "window not hidden");
- return -1;
- }
- if(wunhide(j) == 0){
- strcpy(err, "hide failed");
- return -1;
- }
- return 1;
- case Delete:
- wsendctlmesg(w, Deleted, ZR, nil);
- return 1;
- }
- strcpy(err, "invalid wctl message");
- return -1;
- }
- void
- wctlthread(void *v)
- {
- char *buf, *arg, *dir;
- int cmd, id, pid, hideit, scrollit;
- Rectangle rect;
- char err[ERRMAX];
- Channel *c;
- c = v;
- threadsetname("WCTLTHREAD");
- for(;;){
- buf = recvp(c);
- cmd = parsewctl(&arg, ZR, &rect, &pid, &id, &hideit, &scrollit, &dir, buf, err);
- switch(cmd){
- case New:
- wctlnew(rect, arg, pid, hideit, scrollit, dir, err);
- }
- free(buf);
- }
- }
- void
- wctlproc(void *v)
- {
- char *buf;
- int n, eofs;
- Channel *c;
- threadsetname("WCTLPROC");
- c = v;
- eofs = 0;
- for(;;){
- buf = emalloc(messagesize);
- n = read(wctlfd, buf, messagesize-1); /* room for \0 */
- if(n < 0)
- break;
- if(n == 0){
- if(++eofs > 20)
- break;
- continue;
- }
- eofs = 0;
- buf[n] = '\0';
- sendp(c, buf);
- }
- }
|