123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- /*
- * 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.
- */
- /* Portions of this file are Copyright (C) 2015-2018 Giacomo Tesio <giacomo@tesio.it>
- * See /doc/license/gpl-2.0.txt for details about the licensing.
- */
- /* Portions of this file are Copyright (C) 9front's team.
- * See /doc/license/9front-mit for details about the licensing.
- * See http://code.9front.org/hg/plan9front/ for a list of authors.
- */
- #include <u.h>
- #include <lib9.h>
- #include <draw.h>
- #include <thread.h>
- #include <cursor.h>
- #include <mouse.h>
- #include <keyboard.h>
- #include <frame.h>
- #include <9P2000.h>
- #include <plumb.h>
- #include "dat.h"
- #include "fns.h"
- #include <chartypes.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;
- /* reasonable sizes only please */
- if(Dx(r) > BIG*Dx(screen->r))
- return 0;
- if(Dy(r) > BIG*Dx(screen->r))
- return 0;
- if(Dx(r) < 100 || Dy(r) < 3*font->height)
- return 0;
- /* window must be on screen */
- if(!rectXrect(screen->r, r))
- return 0;
- /* must have some screen and border visible so we can move it out of the way */
- if(rectinrect(screen->r, insetrect(r, Borderwidth)))
- 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(*maxp > max){
- *minp += max-*maxp;
- *maxp = max;
- }
- if(*minp < min){
- *maxp += min-*minp;
- if(*maxp > max)
- *maxp = max;
- *minp = min;
- }
- }
- 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, DNofill);
- else
- i = allocwindow(wscreen, rect, Refbackup, DNofill);
- if(i == nil){
- strcpy(err, Ewalloc);
- return -1;
- }
- new(i, hideit, scrollit, pid, dir, "/cmd/rc", argv);
- free(argv); /* when new() returns, argv and args have been copied */
- return 1;
- }
- int
- wctlcmd(Window *w, Rectangle r, int cmd, char *err)
- {
- Image *i;
- switch(cmd){
- case Move:
- r = Rect(r.min.x, r.min.y, r.min.x+Dx(w->screenr), r.min.y+Dy(w->screenr));
- r = rectonscreen(r);
- /* fall through */
- case Resize:
- if(!goodrect(r)){
- strcpy(err, Ebadwr);
- return -1;
- }
- if(Dx(w->screenr) > 0){
- if(eqrect(r, w->screenr))
- return 1;
- if(w != input){
- strcpy(err, "window not current");
- return -1;
- }
- i = allocwindow(wscreen, r, Refbackup, DNofill);
- } else { /* hidden */
- if(eqrect(r, w->i->r))
- return 1;
- i = allocimage(display, r, w->i->chan, 0, DNofill);
- r = ZR;
- }
- if(i == nil){
- strcpy(err, Ewalloc);
- return -1;
- }
- wsendctlmesg(w, Reshaped, 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:
- if(Dx(w->screenr)<=0){
- strcpy(err, "window is hidden");
- return -1;
- }
- wtopme(w);
- 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:
- switch(wunhide(w)){
- case -1:
- strcpy(err, "window not hidden");
- return -1;
- case 0:
- strcpy(err, "hide failed");
- return -1;
- default:
- break;
- }
- return 1;
- case Delete:
- wsendctlmesg(w, Deleted, ZR, nil);
- return 1;
- }
- strcpy(err, "invalid wctl message");
- return -1;
- }
- int
- writewctl(Xfid *x, char *err)
- {
- int cnt, cmd, id, hideit, scrollit, pid;
- char *arg, *dir;
- Rectangle r;
- Window *w;
- w = x->f->w;
- cnt = x->count;
- x->data[cnt] = '\0';
- id = 0;
- r = rectsubpt(w->screenr, screen->r.min);
- cmd = parsewctl(&arg, r, &r, &pid, &id, &hideit, &scrollit, &dir, x->data, err);
- if(cmd < 0)
- return -1;
- if(id != 0){
- w = wlookid(id);
- if(w == 0){
- strcpy(err, "no such window id");
- return -1;
- }
- }
- switch(cmd){
- case New:
- return wctlnew(r, arg, pid, hideit, scrollit, dir, err);
- case Set:
- if(pid > 0)
- wsetpid(w, pid, 0);
- return 1;
- }
- incref(&w->ref);
- id = wctlcmd(w, r, cmd, err);
- wclose(w);
- return id;
- }
- 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 = jehanne_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);
- }
- }
|