diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/rio/wctl.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/rio/wctl.c')
-rwxr-xr-x | sys/src/cmd/rio/wctl.c | 515 |
1 files changed, 515 insertions, 0 deletions
diff --git a/sys/src/cmd/rio/wctl.c b/sys/src/cmd/rio/wctl.c new file mode 100755 index 000000000..07b882c9f --- /dev/null +++ b/sys/src/cmd/rio/wctl.c @@ -0,0 +1,515 @@ +#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); + } +} |