wctl.c 9.0 KB

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