]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/rio/wctl.c
merge
[plan9front.git] / sys / src / cmd / rio / wctl.c
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <thread.h>
5 #include <cursor.h>
6 #include <mouse.h>
7 #include <keyboard.h>
8 #include <frame.h>
9 #include <fcall.h>
10 #include <plumb.h>
11 #include "dat.h"
12 #include "fns.h"
13 #include <ctype.h>
14
15 char    Ebadwr[]                = "bad rectangle in wctl request";
16 char    Ewalloc[]               = "window allocation failed in wctl request";
17
18 /* >= Top are disallowed if mouse button is pressed */
19 enum
20 {
21         New,
22         Resize,
23         Move,
24         Scroll,
25         Noscroll,
26         Set,
27         Top,
28         Bottom,
29         Current,
30         Hide,
31         Unhide,
32         Delete,
33 };
34
35 static char *cmds[] = {
36         [New]   = "new",
37         [Resize]        = "resize",
38         [Move]  = "move",
39         [Scroll]        = "scroll",
40         [Noscroll]      = "noscroll",
41         [Set]           = "set",
42         [Top]   = "top",
43         [Bottom]        = "bottom",
44         [Current]       = "current",
45         [Hide]  = "hide",
46         [Unhide]        = "unhide",
47         [Delete]        = "delete",
48         nil
49 };
50
51 enum
52 {
53         Cd,
54         Deltax,
55         Deltay,
56         Hidden,
57         Id,
58         Maxx,
59         Maxy,
60         Minx,
61         Miny,
62         PID,
63         R,
64         Scrolling,
65         Noscrolling,
66 };
67
68 static char *params[] = {
69         [Cd]                            = "-cd",
70         [Deltax]                        = "-dx",
71         [Deltay]                        = "-dy",
72         [Hidden]                        = "-hide",
73         [Id]                            = "-id",
74         [Maxx]                  = "-maxx",
75         [Maxy]                  = "-maxy",
76         [Minx]                  = "-minx",
77         [Miny]                  = "-miny",
78         [PID]                           = "-pid",
79         [R]                             = "-r",
80         [Scrolling]                     = "-scroll",
81         [Noscrolling]           = "-noscroll",
82         nil
83 };
84
85 /*
86  * Check that newly created window will be of manageable size
87  */
88 int
89 goodrect(Rectangle r)
90 {
91         if(!eqrect(canonrect(r), r))
92                 return 0;
93         if(Dx(r)<100 || Dy(r)<3*font->height)
94                 return 0;
95         /* must have some screen and border visible so we can move it out of the way */
96         if(Dx(r) >= Dx(screen->r) && Dy(r) >= Dy(screen->r))
97                 return 0;
98         /* reasonable sizes only please */
99         if(Dx(r) > BIG*Dx(screen->r))
100                 return 0;
101         if(Dy(r) > BIG*Dx(screen->r))
102                 return 0;
103         return 1;
104 }
105
106 static
107 int
108 word(char **sp, char *tab[])
109 {
110         char *s, *t;
111         int i;
112
113         s = *sp;
114         while(isspace(*s))
115                 s++;
116         t = s;
117         while(*s!='\0' && !isspace(*s))
118                 s++;
119         for(i=0; tab[i]!=nil; i++)
120                 if(strncmp(tab[i], t, strlen(tab[i])) == 0){
121                         *sp = s;
122                         return i;
123         }
124         return -1;
125 }
126
127 int
128 set(int sign, int neg, int abs, int pos)
129 {
130         if(sign < 0)
131                 return neg;
132         if(sign > 0)
133                 return pos;
134         return abs;
135 }
136
137 Rectangle
138 newrect(void)
139 {
140         static int i = 0;
141         int minx, miny, dx, dy;
142
143         dx = min(600, Dx(screen->r) - 2*Borderwidth);
144         dy = min(400, Dy(screen->r) - 2*Borderwidth);
145         minx = 32 + 16*i;
146         miny = 32 + 16*i;
147         i++;
148         i %= 10;
149
150         return Rect(minx, miny, minx+dx, miny+dy);
151 }
152
153 void
154 shift(int *minp, int *maxp, int min, int max)
155 {
156         if(*minp < min){
157                 *maxp += min-*minp;
158                 *minp = min;
159         }
160         if(*maxp > max){
161                 *minp += max-*maxp;
162                 *maxp = max;
163         }
164 }
165
166 Rectangle
167 rectonscreen(Rectangle r)
168 {
169         shift(&r.min.x, &r.max.x, screen->r.min.x, screen->r.max.x);
170         shift(&r.min.y, &r.max.y, screen->r.min.y, screen->r.max.y);
171         return r;
172 }
173
174 /* permit square brackets, in the manner of %R */
175 int
176 riostrtol(char *s, char **t)
177 {
178         int n;
179
180         while(*s!='\0' && (*s==' ' || *s=='\t' || *s=='['))
181                 s++;
182         if(*s == '[')
183                 s++;
184         n = strtol(s, t, 10);
185         if(*t != s)
186                 while((*t)[0] == ']')
187                         (*t)++;
188         return n;
189 }
190
191
192 int
193 parsewctl(char **argp, Rectangle r, Rectangle *rp, int *pidp, int *idp, int *hiddenp, int *scrollingp, char **cdp, char *s, char *err)
194 {
195         int cmd, param, xy, sign;
196         char *t;
197
198         *pidp = 0;
199         *hiddenp = 0;
200         *scrollingp = scrolling;
201         *cdp = nil;
202         cmd = word(&s, cmds);
203         if(cmd < 0){
204                 strcpy(err, "unrecognized wctl command");
205                 return -1;
206         }
207         if(cmd == New)
208                 r = newrect();
209
210         strcpy(err, "missing or bad wctl parameter");
211         while((param = word(&s, params)) >= 0){
212                 switch(param){  /* special cases */
213                 case Hidden:
214                         *hiddenp = 1;
215                         continue;
216                 case Scrolling:
217                         *scrollingp = 1;
218                         continue;
219                 case Noscrolling:
220                         *scrollingp = 0;
221                         continue;
222                 case R:
223                         r.min.x = riostrtol(s, &t);
224                         if(t == s)
225                                 return -1;
226                         s = t;
227                         r.min.y = riostrtol(s, &t);
228                         if(t == s)
229                                 return -1;
230                         s = t;
231                         r.max.x = riostrtol(s, &t);
232                         if(t == s)
233                                 return -1;
234                         s = t;
235                         r.max.y = riostrtol(s, &t);
236                         if(t == s)
237                                 return -1;
238                         s = t;
239                         continue;
240                 }
241                 while(isspace(*s))
242                         s++;
243                 if(param == Cd){
244                         *cdp = s;
245                         while(*s && !isspace(*s))
246                                 s++;
247                         if(*s != '\0')
248                                 *s++ = '\0';
249                         continue;
250                 }
251                 sign = 0;
252                 if(*s == '-'){
253                         sign = -1;
254                         s++;
255                 }else if(*s == '+'){
256                         sign = +1;
257                         s++;
258                 }
259                 if(!isdigit(*s))
260                         return -1;
261                 xy = riostrtol(s, &s);
262                 switch(param){
263                 case -1:
264                         strcpy(err, "unrecognized wctl parameter");
265                         return -1;
266                 case Minx:
267                         r.min.x = set(sign, r.min.x-xy, xy, r.min.x+xy);
268                         break;
269                 case Miny:
270                         r.min.y = set(sign, r.min.y-xy, xy, r.min.y+xy);
271                         break;
272                 case Maxx:
273                         r.max.x = set(sign, r.max.x-xy, xy, r.max.x+xy);
274                         break;
275                 case Maxy:
276                         r.max.y = set(sign, r.max.y-xy, xy, r.max.y+xy);
277                         break;
278                 case Deltax:
279                         r.max.x = set(sign, r.max.x-xy, r.min.x+xy, r.max.x+xy);
280                         break;
281                 case Deltay:
282                         r.max.y = set(sign, r.max.y-xy, r.min.y+xy, r.max.y+xy);
283                         break;
284                 case Id:
285                         if(idp != nil)
286                                 *idp = xy;
287                         break;
288                 case PID:
289                         if(pidp != nil)
290                                 *pidp = xy;
291                         break;
292                 }
293         }
294
295         *rp = rectonscreen(rectaddpt(r, screen->r.min));
296
297         while(isspace(*s))
298                 s++;
299         if(cmd!=New && *s!='\0'){
300                 strcpy(err, "extraneous text in wctl message");
301                 return -1;
302         }
303
304         if(argp)
305                 *argp = s;
306
307         return cmd;
308 }
309
310 int
311 wctlnew(Rectangle rect, char *arg, int pid, int hideit, int scrollit, char *dir, char *err)
312 {
313         char **argv;
314         Image *i;
315
316         if(!goodrect(rect)){
317                 strcpy(err, Ebadwr);
318                 return -1;
319         }
320         argv = emalloc(4*sizeof(char*));
321         argv[0] = "rc";
322         argv[1] = "-c";
323         while(isspace(*arg))
324                 arg++;
325         if(*arg == '\0'){
326                 argv[1] = "-i";
327                 argv[2] = nil;
328         }else{
329                 argv[2] = arg;
330                 argv[3] = nil;
331         }
332         if(hideit)
333                 i = allocimage(display, rect, screen->chan, 0, DWhite);
334         else
335                 i = allocwindow(wscreen, rect, Refbackup, DWhite);
336         if(i == nil){
337                 strcpy(err, Ewalloc);
338                 return -1;
339         }
340         border(i, rect, Selborder, red, ZP);
341
342         new(i, hideit, scrollit, pid, dir, "/bin/rc", argv);
343
344         free(argv);     /* when new() returns, argv and args have been copied */
345         return 1;
346 }
347
348 int
349 writewctl(Xfid *x, char *err)
350 {
351         int cnt, cmd, j, id, hideit, scrollit, pid;
352         Image *i;
353         char *arg, *dir;
354         Rectangle rect;
355         Window *w;
356
357         w = x->f->w;
358         cnt = x->count;
359         x->data[cnt] = '\0';
360         id = 0;
361
362         rect = rectsubpt(w->screenr, screen->r.min);
363         cmd = parsewctl(&arg, rect, &rect, &pid, &id, &hideit, &scrollit, &dir, x->data, err);
364         if(cmd < 0)
365                 return -1;
366
367         if(mouse->buttons!=0 && cmd>=Top){
368                 strcpy(err, "action disallowed when mouse active");
369                 return -1;
370         }
371
372         if(id != 0){
373                 for(j=0; j<nwindow; j++)
374                         if(window[j]->id == id)
375                                 break;
376                 if(j == nwindow){
377                         strcpy(err, "no such window id");
378                         return -1;
379                 }
380                 w = window[j];
381                 if(w->deleted || w->i==nil){
382                         strcpy(err, "window deleted");
383                         return -1;
384                 }
385         }
386
387         switch(cmd){
388         case New:
389                 return wctlnew(rect, arg, pid, hideit, scrollit, dir, err);
390         case Set:
391                 if(pid > 0)
392                         wsetpid(w, pid, 0);
393                 return 1;
394         case Move:
395                 rect = Rect(rect.min.x, rect.min.y, rect.min.x+Dx(w->screenr), rect.min.y+Dy(w->screenr));
396                 rect = rectonscreen(rect);
397                 /* fall through */
398         case Resize:
399                 if(!goodrect(rect)){
400                         strcpy(err, Ebadwr);
401                         return -1;
402                 }
403                 if(eqrect(rect, w->screenr))
404                         return 1;
405                 i = allocwindow(wscreen, rect, Refbackup, DWhite);
406                 if(i == nil){
407                         strcpy(err, Ewalloc);
408                         return -1;
409                 }
410                 border(i, rect, Selborder, red, ZP);
411                 wsendctlmesg(w, Reshaped, i->r, i);
412                 return 1;
413         case Scroll:
414                 w->scrolling = 1;
415                 wshow(w, w->nr);
416                 wsendctlmesg(w, Wakeup, ZR, nil);
417                 return 1;
418         case Noscroll:
419                 w->scrolling = 0;
420                 wsendctlmesg(w, Wakeup, ZR, nil);
421                 return 1;
422         case Top:
423                 wtopme(w);
424                 return 1;
425         case Bottom:
426                 wbottomme(w);
427                 return 1;
428         case Current:
429                 wcurrent(w);
430                 return 1;
431         case Hide:
432                 switch(whide(w)){
433                 case -1:
434                         strcpy(err, "window already hidden");
435                         return -1;
436                 case 0:
437                         strcpy(err, "hide failed");
438                         return -1;
439                 default:
440                         break;
441                 }
442                 return 1;
443         case Unhide:
444                 for(j=0; j<nhidden; j++)
445                         if(hidden[j] == w)
446                                 break;
447                 if(j == nhidden){
448                         strcpy(err, "window not hidden");
449                         return -1;
450                 }
451                 if(wunhide(j) == 0){
452                         strcpy(err, "hide failed");
453                         return -1;
454                 }
455                 return 1;
456         case Delete:
457                 wsendctlmesg(w, Deleted, ZR, nil);
458                 return 1;
459         }
460         strcpy(err, "invalid wctl message");
461         return -1;
462 }
463
464 void
465 wctlthread(void *v)
466 {
467         char *buf, *arg, *dir;
468         int cmd, id, pid, hideit, scrollit;
469         Rectangle rect;
470         char err[ERRMAX];
471         Channel *c;
472
473         c = v;
474
475         threadsetname("WCTLTHREAD");
476
477         for(;;){
478                 buf = recvp(c);
479                 cmd = parsewctl(&arg, ZR, &rect, &pid, &id, &hideit, &scrollit, &dir, buf, err);
480
481                 switch(cmd){
482                 case New:
483                         wctlnew(rect, arg, pid, hideit, scrollit, dir, err);
484                 }
485                 free(buf);
486         }
487 }
488
489 void
490 wctlproc(void *v)
491 {
492         char *buf;
493         int n, eofs;
494         Channel *c;
495
496         threadsetname("WCTLPROC");
497         c = v;
498
499         eofs = 0;
500         for(;;){
501                 buf = emalloc(messagesize);
502                 n = read(wctlfd, buf, messagesize-1);   /* room for \0 */
503                 if(n < 0)
504                         break;
505                 if(n == 0){
506                         if(++eofs > 20)
507                                 break;
508                         continue;
509                 }
510                 eofs = 0;
511
512                 buf[n] = '\0';
513                 sendp(c, buf);
514         }
515 }