]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/rio/wctl.c
rio: stop serving kbdin file (thanks eekee)
[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*Dx(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(eqrect(r, w->screenr))
364                         return 1;
365                 if(!goodrect(r)){
366                         strcpy(err, Ebadwr);
367                         return -1;
368                 }
369                 if(w != input){
370                         strcpy(err, "window not current");
371                         return -1;
372                 }
373                 i = allocwindow(wscreen, r, Refbackup, DNofill);
374                 if(i == nil){
375                         strcpy(err, Ewalloc);
376                         return -1;
377                 }
378                 wsendctlmesg(w, Reshaped, i->r, i);
379                 return 1;
380         case Scroll:
381                 w->scrolling = 1;
382                 wshow(w, w->nr);
383                 wsendctlmesg(w, Wakeup, ZR, nil);
384                 return 1;
385         case Noscroll:
386                 w->scrolling = 0;
387                 wsendctlmesg(w, Wakeup, ZR, nil);
388                 return 1;
389         case Top:
390                 wtopme(w);
391                 return 1;
392         case Bottom:
393                 wbottomme(w);
394                 return 1;
395         case Current:
396                 wtopme(w);
397                 wcurrent(w);
398                 return 1;
399         case Hide:
400                 switch(whide(w)){
401                 case -1:
402                         strcpy(err, "window already hidden");
403                         return -1;
404                 case 0:
405                         strcpy(err, "hide failed");
406                         return -1;
407                 default:
408                         break;
409                 }
410                 return 1;
411         case Unhide:
412                 switch(wunhide(w)){
413                 case -1:
414                         strcpy(err, "window not hidden");
415                         return -1;
416                 case 0:
417                         strcpy(err, "hide failed");
418                         return -1;
419                 default:
420                         break;
421                 }
422                 return 1;
423         case Delete:
424                 wsendctlmesg(w, Deleted, ZR, nil);
425                 return 1;
426         }
427
428         strcpy(err, "invalid wctl message");
429         return -1;
430 }
431
432 int
433 writewctl(Xfid *x, char *err)
434 {
435         int cnt, cmd, id, hideit, scrollit, pid;
436         char *arg, *dir;
437         Rectangle r;
438         Window *w;
439
440         w = x->f->w;
441         cnt = x->count;
442         x->data[cnt] = '\0';
443         id = 0;
444
445         r = rectsubpt(w->screenr, screen->r.min);
446         cmd = parsewctl(&arg, r, &r, &pid, &id, &hideit, &scrollit, &dir, x->data, err);
447         if(cmd < 0)
448                 return -1;
449
450         if(id != 0){
451                 w = wlookid(id);
452                 if(w == 0){
453                         strcpy(err, "no such window id");
454                         return -1;
455                 }
456         }
457
458         switch(cmd){
459         case New:
460                 return wctlnew(r, arg, pid, hideit, scrollit, dir, err);
461         case Set:
462                 if(pid > 0)
463                         wsetpid(w, pid, 0);
464                 return 1;
465         }
466
467         incref(w);
468         id = wctlcmd(w, r, cmd, err);
469         wclose(w);
470
471         return id;
472 }
473
474 void
475 wctlthread(void *v)
476 {
477         char *buf, *arg, *dir;
478         int cmd, id, pid, hideit, scrollit;
479         Rectangle rect;
480         char err[ERRMAX];
481         Channel *c;
482
483         c = v;
484
485         threadsetname("WCTLTHREAD");
486
487         for(;;){
488                 buf = recvp(c);
489                 cmd = parsewctl(&arg, ZR, &rect, &pid, &id, &hideit, &scrollit, &dir, buf, err);
490
491                 switch(cmd){
492                 case New:
493                         wctlnew(rect, arg, pid, hideit, scrollit, dir, err);
494                 }
495                 free(buf);
496         }
497 }
498
499 void
500 wctlproc(void *v)
501 {
502         char *buf;
503         int n, eofs;
504         Channel *c;
505
506         threadsetname("WCTLPROC");
507         c = v;
508
509         eofs = 0;
510         for(;;){
511                 buf = emalloc(messagesize);
512                 n = read(wctlfd, buf, messagesize-1);   /* room for \0 */
513                 if(n < 0)
514                         break;
515                 if(n == 0){
516                         if(++eofs > 20)
517                                 break;
518                         continue;
519                 }
520                 eofs = 0;
521
522                 buf[n] = '\0';
523                 sendp(c, buf);
524         }
525 }