]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/rio/wctl.c
tweak selection criteria
[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         /* reasonable sizes only please */
94         if(Dx(r) > BIG*Dx(screen->r))
95                 return 0;
96         if(Dy(r) > BIG*Dy(screen->r))
97                 return 0;
98         if(Dx(r) < 100 || Dy(r) < 3*font->height)
99                 return 0;
100         /* window must be on screen */
101         if(!rectXrect(screen->r, r))
102                 return 0;
103         /* must have some screen and border visible so we can move it out of the way */
104         if(rectinrect(screen->r, insetrect(r, Borderwidth)))
105                 return 0;
106         return 1;
107 }
108
109 static
110 int
111 word(char **sp, char *tab[])
112 {
113         char *s, *t;
114         int i;
115
116         s = *sp;
117         while(isspace(*s))
118                 s++;
119         t = s;
120         while(*s!='\0' && !isspace(*s))
121                 s++;
122         for(i=0; tab[i]!=nil; i++)
123                 if(strncmp(tab[i], t, strlen(tab[i])) == 0){
124                         *sp = s;
125                         return i;
126         }
127         return -1;
128 }
129
130 int
131 set(int sign, int neg, int abs, int pos)
132 {
133         if(sign < 0)
134                 return neg;
135         if(sign > 0)
136                 return pos;
137         return abs;
138 }
139
140 Rectangle
141 newrect(void)
142 {
143         static int i = 0;
144         int minx, miny, dx, dy;
145
146         dx = min(600, Dx(screen->r) - 2*Borderwidth);
147         dy = min(400, Dy(screen->r) - 2*Borderwidth);
148         minx = 32 + 16*i;
149         miny = 32 + 16*i;
150         i++;
151         i %= 10;
152
153         return Rect(minx, miny, minx+dx, miny+dy);
154 }
155
156 void
157 shift(int *minp, int *maxp, int min, int max)
158 {
159         if(*maxp > max){
160                 *minp += max-*maxp;
161                 *maxp = max;
162         }
163         if(*minp < min){
164                 *maxp += min-*minp;
165                 if(*maxp > max)
166                         *maxp = max;
167                 *minp = min;
168         }
169 }
170
171 Rectangle
172 rectonscreen(Rectangle r)
173 {
174         shift(&r.min.x, &r.max.x, screen->r.min.x, screen->r.max.x);
175         shift(&r.min.y, &r.max.y, screen->r.min.y, screen->r.max.y);
176         return r;
177 }
178
179 /* permit square brackets, in the manner of %R */
180 int
181 riostrtol(char *s, char **t)
182 {
183         int n;
184
185         while(*s!='\0' && (*s==' ' || *s=='\t' || *s=='['))
186                 s++;
187         if(*s == '[')
188                 s++;
189         n = strtol(s, t, 10);
190         if(*t != s)
191                 while((*t)[0] == ']')
192                         (*t)++;
193         return n;
194 }
195
196
197 int
198 parsewctl(char **argp, Rectangle r, Rectangle *rp, int *pidp, int *idp, int *hiddenp, int *scrollingp, char **cdp, char *s, char *err)
199 {
200         int cmd, param, xy, sign;
201         char *t;
202
203         *pidp = 0;
204         *hiddenp = 0;
205         *scrollingp = scrolling;
206         *cdp = nil;
207         cmd = word(&s, cmds);
208         if(cmd < 0){
209                 strcpy(err, "unrecognized wctl command");
210                 return -1;
211         }
212         if(cmd == New)
213                 r = newrect();
214
215         strcpy(err, "missing or bad wctl parameter");
216         while((param = word(&s, params)) >= 0){
217                 switch(param){  /* special cases */
218                 case Hidden:
219                         *hiddenp = 1;
220                         continue;
221                 case Scrolling:
222                         *scrollingp = 1;
223                         continue;
224                 case Noscrolling:
225                         *scrollingp = 0;
226                         continue;
227                 case R:
228                         r.min.x = riostrtol(s, &t);
229                         if(t == s)
230                                 return -1;
231                         s = t;
232                         r.min.y = riostrtol(s, &t);
233                         if(t == s)
234                                 return -1;
235                         s = t;
236                         r.max.x = riostrtol(s, &t);
237                         if(t == s)
238                                 return -1;
239                         s = t;
240                         r.max.y = riostrtol(s, &t);
241                         if(t == s)
242                                 return -1;
243                         s = t;
244                         continue;
245                 }
246                 while(isspace(*s))
247                         s++;
248                 if(param == Cd){
249                         *cdp = s;
250                         while(*s && !isspace(*s))
251                                 s++;
252                         if(*s != '\0')
253                                 *s++ = '\0';
254                         continue;
255                 }
256                 sign = 0;
257                 if(*s == '-'){
258                         sign = -1;
259                         s++;
260                 }else if(*s == '+'){
261                         sign = +1;
262                         s++;
263                 }
264                 if(!isdigit(*s))
265                         return -1;
266                 xy = riostrtol(s, &s);
267                 switch(param){
268                 case -1:
269                         strcpy(err, "unrecognized wctl parameter");
270                         return -1;
271                 case Minx:
272                         r.min.x = set(sign, r.min.x-xy, xy, r.min.x+xy);
273                         break;
274                 case Miny:
275                         r.min.y = set(sign, r.min.y-xy, xy, r.min.y+xy);
276                         break;
277                 case Maxx:
278                         r.max.x = set(sign, r.max.x-xy, xy, r.max.x+xy);
279                         break;
280                 case Maxy:
281                         r.max.y = set(sign, r.max.y-xy, xy, r.max.y+xy);
282                         break;
283                 case Deltax:
284                         r.max.x = set(sign, r.max.x-xy, r.min.x+xy, r.max.x+xy);
285                         break;
286                 case Deltay:
287                         r.max.y = set(sign, r.max.y-xy, r.min.y+xy, r.max.y+xy);
288                         break;
289                 case Id:
290                         if(idp != nil)
291                                 *idp = xy;
292                         break;
293                 case PID:
294                         if(pidp != nil)
295                                 *pidp = xy;
296                         break;
297                 }
298         }
299
300         *rp = rectonscreen(rectaddpt(r, screen->r.min));
301
302         while(isspace(*s))
303                 s++;
304         if(cmd!=New && *s!='\0'){
305                 strcpy(err, "extraneous text in wctl message");
306                 return -1;
307         }
308
309         if(argp)
310                 *argp = s;
311
312         return cmd;
313 }
314
315 int
316 wctlnew(Rectangle rect, char *arg, int pid, int hideit, int scrollit, char *dir, char *err)
317 {
318         char **argv;
319         Image *i;
320
321         if(!goodrect(rect)){
322                 strcpy(err, Ebadwr);
323                 return -1;
324         }
325         argv = emalloc(4*sizeof(char*));
326         argv[0] = "rc";
327         argv[1] = "-c";
328         while(isspace(*arg))
329                 arg++;
330         if(*arg == '\0'){
331                 argv[1] = "-i";
332                 argv[2] = nil;
333         }else{
334                 argv[2] = arg;
335                 argv[3] = nil;
336         }
337         if(hideit)
338                 i = allocimage(display, rect, screen->chan, 0, DNofill);
339         else
340                 i = allocwindow(wscreen, rect, Refbackup, DNofill);
341         if(i == nil){
342                 strcpy(err, Ewalloc);
343                 return -1;
344         }
345
346         new(i, hideit, scrollit, pid, dir, "/bin/rc", argv);
347
348         free(argv);     /* when new() returns, argv and args have been copied */
349         return 1;
350 }
351
352 int
353 wctlcmd(Window *w, Rectangle r, int cmd, char *err)
354 {
355         Image *i;
356
357         switch(cmd){
358         case Move:
359                 r = Rect(r.min.x, r.min.y, r.min.x+Dx(w->screenr), r.min.y+Dy(w->screenr));
360                 r = rectonscreen(r);
361                 /* fall through */
362         case Resize:
363                 if(!goodrect(r)){
364                         strcpy(err, Ebadwr);
365                         return -1;
366                 }
367                 if(Dx(w->screenr) > 0){
368                         if(eqrect(r, w->screenr))
369                                 return 1;
370                         if(w != input){
371                                 strcpy(err, "window not current");
372                                 return -1;
373                         }
374                         i = allocwindow(wscreen, r, Refbackup, DNofill);
375                 } else { /* hidden */
376                         if(eqrect(r, w->i->r))
377                                 return 1;
378                         i = allocimage(display, r, w->i->chan, 0, DNofill);
379                         r = ZR;
380                 }
381                 if(i == nil){
382                         strcpy(err, Ewalloc);
383                         return -1;
384                 }
385                 wsendctlmesg(w, Reshaped, r, i);
386                 return 1;
387         case Scroll:
388                 w->scrolling = 1;
389                 wshow(w, w->nr);
390                 wsendctlmesg(w, Wakeup, ZR, nil);
391                 return 1;
392         case Noscroll:
393                 w->scrolling = 0;
394                 wsendctlmesg(w, Wakeup, ZR, nil);
395                 return 1;
396         case Top:
397                 wtopme(w);
398                 return 1;
399         case Bottom:
400                 wbottomme(w);
401                 return 1;
402         case Current:
403                 if(Dx(w->screenr)<=0){
404                         strcpy(err, "window is hidden");
405                         return -1;
406                 }
407                 wtopme(w);
408                 wcurrent(w);
409                 return 1;
410         case Hide:
411                 switch(whide(w)){
412                 case -1:
413                         strcpy(err, "window already hidden");
414                         return -1;
415                 case 0:
416                         strcpy(err, "hide failed");
417                         return -1;
418                 default:
419                         break;
420                 }
421                 return 1;
422         case Unhide:
423                 switch(wunhide(w)){
424                 case -1:
425                         strcpy(err, "window not hidden");
426                         return -1;
427                 case 0:
428                         strcpy(err, "hide failed");
429                         return -1;
430                 default:
431                         break;
432                 }
433                 return 1;
434         case Delete:
435                 wsendctlmesg(w, Deleted, ZR, nil);
436                 return 1;
437         }
438
439         strcpy(err, "invalid wctl message");
440         return -1;
441 }
442
443 int
444 writewctl(Xfid *x, char *err)
445 {
446         int cnt, cmd, id, hideit, scrollit, pid;
447         char *arg, *dir;
448         Rectangle r;
449         Window *w;
450
451         w = x->f->w;
452         cnt = x->count;
453         x->data[cnt] = '\0';
454         id = 0;
455
456         r = rectsubpt(w->screenr, screen->r.min);
457         cmd = parsewctl(&arg, r, &r, &pid, &id, &hideit, &scrollit, &dir, x->data, err);
458         if(cmd < 0)
459                 return -1;
460
461         if(id != 0){
462                 w = wlookid(id);
463                 if(w == 0){
464                         strcpy(err, "no such window id");
465                         return -1;
466                 }
467         }
468
469         switch(cmd){
470         case New:
471                 return wctlnew(r, arg, pid, hideit, scrollit, dir, err);
472         case Set:
473                 if(pid > 0)
474                         wsetpid(w, pid, 0);
475                 return 1;
476         }
477
478         incref(w);
479         id = wctlcmd(w, r, cmd, err);
480         wclose(w);
481
482         return id;
483 }
484
485 void
486 wctlthread(void *v)
487 {
488         char *buf, *arg, *dir;
489         int cmd, id, pid, hideit, scrollit;
490         Rectangle rect;
491         char err[ERRMAX];
492         Channel *c;
493
494         c = v;
495
496         threadsetname("WCTLTHREAD");
497
498         for(;;){
499                 buf = recvp(c);
500                 cmd = parsewctl(&arg, ZR, &rect, &pid, &id, &hideit, &scrollit, &dir, buf, err);
501
502                 switch(cmd){
503                 case New:
504                         wctlnew(rect, arg, pid, hideit, scrollit, dir, err);
505                 }
506                 free(buf);
507         }
508 }
509
510 void
511 wctlproc(void *v)
512 {
513         char *buf;
514         int n, eofs;
515         Channel *c;
516
517         threadsetname("WCTLPROC");
518         c = v;
519
520         eofs = 0;
521         for(;;){
522                 buf = emalloc(messagesize);
523                 n = read(wctlfd, buf, messagesize-1);   /* room for \0 */
524                 if(n < 0)
525                         break;
526                 if(n == 0){
527                         if(++eofs > 20)
528                                 break;
529                         continue;
530                 }
531                 eofs = 0;
532
533                 buf[n] = '\0';
534                 sendp(c, buf);
535         }
536 }