jay.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305
  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 <jay.h>
  20. #include "dat.h"
  21. #include "fns.h"
  22. void resize(void);
  23. void move(void);
  24. void delete(void);
  25. void hide(void);
  26. void unhide(int);
  27. void newtile(int);
  28. Image *sweep(void);
  29. Image *bandsize(Window*);
  30. Image* drag(Window*, Rectangle*);
  31. void refresh(Rectangle);
  32. void resized(void);
  33. Channel *exitchan; /* chan(int) */
  34. Channel *winclosechan; /* chan(Window*); */
  35. Rectangle viewr;
  36. int threadrforkflag = 0; /* should be RFENVG but that hides jay from plumber */
  37. void mousethread(void*);
  38. void keyboardthread(void*);
  39. void winclosethread(void*);
  40. void deletethread(void*);
  41. void initcmd(void*);
  42. char *fontname;
  43. int mainpid;
  44. enum
  45. {
  46. New,
  47. Reshape,
  48. Move,
  49. Delete,
  50. Hide,
  51. Exit,
  52. };
  53. enum
  54. {
  55. Cut,
  56. Paste,
  57. Snarf,
  58. Plumb,
  59. Send,
  60. Scroll,
  61. };
  62. char *menu2str[] = {
  63. [Cut] = "cut",
  64. [Paste] = "paste",
  65. [Snarf] = "copy",
  66. [Plumb] = "plumb",
  67. [Send] = "send",
  68. [Scroll] = "scroll",
  69. nil
  70. };
  71. Menu menu2 =
  72. {
  73. menu2str
  74. };
  75. int Hidden = Exit+1;
  76. char *menu3str[100] = {
  77. [New] = "New",
  78. [Reshape] = "Resize",
  79. [Move] = "Move",
  80. [Delete] = "Delete",
  81. [Hide] = "Hide",
  82. [Exit] = "Exit",
  83. nil
  84. };
  85. Menu menu3 =
  86. {
  87. menu3str
  88. };
  89. char *rcargv[] = { "rc", "-i", nil };
  90. char *kbdargv[] = { "rc", "-c", nil, nil };
  91. int errorshouldabort = 0;
  92. void
  93. derror(Display* d, char *errorstr)
  94. {
  95. error(errorstr);
  96. }
  97. void
  98. usage(void)
  99. {
  100. fprint(2, "usage: jay [-f font] [-i initcmd] [-k kbdcmd] [-s]\n");
  101. exits("usage");
  102. }
  103. void
  104. threadmain(int argc, char *argv[])
  105. {
  106. char *initstr, *kbdin, *s;
  107. char buf[256];
  108. if(strstr(argv[0], ".out") == nil){
  109. menu3str[Exit] = nil;
  110. Hidden--;
  111. }
  112. initstr = nil;
  113. kbdin = nil;
  114. maxtab = 0;
  115. ARGBEGIN{
  116. case 'f':
  117. fontname = ARGF();
  118. if(fontname == nil)
  119. usage();
  120. break;
  121. case 'i':
  122. initstr = ARGF();
  123. if(initstr == nil)
  124. usage();
  125. break;
  126. case 'k':
  127. if(kbdin != nil)
  128. usage();
  129. kbdin = ARGF();
  130. if(kbdin == nil)
  131. usage();
  132. break;
  133. case 's':
  134. scrolling = TRUE;
  135. break;
  136. }ARGEND
  137. mainpid = getpid();
  138. if(getwd(buf, sizeof buf) == nil)
  139. startdir = estrdup(".");
  140. else
  141. startdir = estrdup(buf);
  142. if(fontname == nil)
  143. fontname = getenv("font");
  144. if(fontname == nil)
  145. fontname = "/lib/font/bit/lucm/unicode.9.font";
  146. s = getenv("tabstop");
  147. if(s != nil)
  148. maxtab = strtol(s, nil, 0);
  149. if(maxtab == 0)
  150. maxtab = 4;
  151. free(s);
  152. /* check font before barging ahead */
  153. if(access(fontname, 0) < 0){
  154. fprint(2, "jay: can't access %s: %r\n", fontname);
  155. exits("font open");
  156. }
  157. putenv("font", fontname);
  158. snarffd = open("/dev/snarf", OREAD|OCEXEC);
  159. if(geninitdraw(nil, derror, nil, "jay", nil, Refnone) < 0){
  160. fprint(2, "jay: can't open display: %r\n");
  161. exits("display open");
  162. }
  163. iconinit();
  164. view = screen;
  165. viewr = view->r;
  166. windowspace = viewr;
  167. mousectl = initmouse(nil, screen);
  168. if(mousectl == nil)
  169. error("can't find mouse");
  170. mouse = (Mouse *)mousectl;
  171. jaysetcursor(nil, 1);
  172. keyboardctl = initkeyboard(nil);
  173. if(keyboardctl == nil)
  174. error("can't find keyboard");
  175. wscreen = allocscreen(screen, background, 0);
  176. if(wscreen == nil)
  177. error("can't allocate screen");
  178. draw(view, viewr, background, nil, viewr.min);
  179. flushimage(display, 1);
  180. exitchan = chancreate(sizeof(int), 0);
  181. winclosechan = chancreate(sizeof(Window*), 0);
  182. deletechan = chancreate(sizeof(char*), 0);
  183. initpanel();
  184. timerinit();
  185. threadcreate(keyboardthread, nil, STACK);
  186. threadcreate(mousethread, nil, STACK);
  187. threadcreate(winclosethread, nil, STACK);
  188. threadcreate(deletethread, nil, STACK);
  189. filsys = filsysinit(xfidinit());
  190. if(filsys == nil)
  191. fprint(2, "jay: can't create file system server: %r\n");
  192. else{
  193. errorshouldabort = 1; /* suicide if there's trouble after this */
  194. #if 0
  195. if(initstr)
  196. proccreate(initcmd, initstr, STACK);
  197. if(kbdin){
  198. kbdargv[2] = kbdin;
  199. r = screen->r;
  200. r.max.x = r.min.x+300;
  201. r.max.y = r.min.y+80;
  202. i = allocwindow(wscreen, r, Refbackup, DWhite);
  203. wkeyboard = new(i, FALSE, scrolling, 0, nil, "/bin/rc", kbdargv);
  204. if(wkeyboard == nil)
  205. error("can't create keyboard window");
  206. }
  207. #endif
  208. threadnotify(shutdown, 1);
  209. recv(exitchan, nil);
  210. }
  211. killprocs();
  212. threadexitsall(nil);
  213. }
  214. /*
  215. * /dev/snarf updates when the file is closed, so we must open our own
  216. * fd here rather than use snarffd
  217. */
  218. void
  219. putsnarf(void)
  220. {
  221. int fd, i, n;
  222. if(snarffd<0 || nsnarf==0)
  223. return;
  224. fd = open("/dev/snarf", OWRITE);
  225. if(fd < 0)
  226. return;
  227. /* snarf buffer could be huge, so fprint will truncate; do it in blocks */
  228. for(i=0; i<nsnarf; i+=n){
  229. n = nsnarf-i;
  230. if(n >= 256)
  231. n = 256;
  232. if(fprint(fd, "%.*S", n, snarf+i) < 0)
  233. break;
  234. }
  235. close(fd);
  236. }
  237. void
  238. getsnarf(void)
  239. {
  240. int i, n, nb, nulls;
  241. char *sn, buf[1024];
  242. if(snarffd < 0)
  243. return;
  244. sn = nil;
  245. i = 0;
  246. seek(snarffd, 0, 0);
  247. while((n = read(snarffd, buf, sizeof buf)) > 0){
  248. sn = erealloc(sn, i+n+1);
  249. memmove(sn+i, buf, n);
  250. i += n;
  251. sn[i] = 0;
  252. }
  253. if(i > 0){
  254. snarf = runerealloc(snarf, i+1);
  255. cvttorunes(sn, i, snarf, &nb, &nsnarf, &nulls);
  256. free(sn);
  257. }
  258. }
  259. void
  260. initcmd(void *arg)
  261. {
  262. char *cmd;
  263. cmd = arg;
  264. rfork(RFENVG|RFFDG|RFNOTEG|RFNAMEG);
  265. procexecl(nil, "/bin/rc", "rc", "-c", cmd, nil);
  266. fprint(2, "jay: exec failed: %r\n");
  267. exits("exec");
  268. }
  269. char *oknotes[] =
  270. {
  271. "delete",
  272. "hangup",
  273. "kill",
  274. "exit",
  275. nil
  276. };
  277. int
  278. shutdown(void * vacio, char *msg)
  279. {
  280. int i;
  281. static Lock shutdownlk;
  282. killprocs();
  283. for(i=0; oknotes[i]; i++)
  284. if(strncmp(oknotes[i], msg, strlen(oknotes[i])) == 0){
  285. lock(&shutdownlk); /* only one can threadexitsall */
  286. threadexitsall(msg);
  287. }
  288. fprint(2, "jay %d: abort: %s\n", getpid(), msg);
  289. abort();
  290. exits(msg);
  291. return 0;
  292. }
  293. void
  294. killprocs(void)
  295. {
  296. int i;
  297. for(i=0; i<nwindow; i++)
  298. postnote(PNGROUP, window[i]->pid, "hangup");
  299. }
  300. void
  301. keyboardthread(void* v)
  302. {
  303. Rune buf[2][20], *rp;
  304. int n, i;
  305. threadsetname("keyboardthread");
  306. n = 0;
  307. for(;;){
  308. rp = buf[n];
  309. n = 1-n;
  310. recv(keyboardctl->c, rp);
  311. for(i=1; i<nelem(buf[0])-1; i++)
  312. if(nbrecv(keyboardctl->c, rp+i) <= 0)
  313. break;
  314. rp[i] = L'\0';
  315. if(input != nil)
  316. sendp(input->ck, rp);
  317. }
  318. }
  319. /*
  320. * Used by /dev/kbdin
  321. */
  322. void
  323. keyboardsend(char *s, int cnt)
  324. {
  325. Rune *r;
  326. int i, nb, nr;
  327. r = runemalloc(cnt);
  328. /* BUGlet: partial runes will be converted to error runes */
  329. cvttorunes(s, cnt, r, &nb, &nr, nil);
  330. for(i=0; i<nr; i++)
  331. send(keyboardctl->c, &r[i]);
  332. free(r);
  333. }
  334. int
  335. portion(int x, int lo, int hi)
  336. {
  337. x -= lo;
  338. hi -= lo;
  339. if(x < 20)
  340. return 0;
  341. if(x > hi-20)
  342. return 2;
  343. return 1;
  344. }
  345. int
  346. whichcorner(Window *w, Point p)
  347. {
  348. int i, j;
  349. i = portion(p.x, w->r.min.x, w->r.max.x);
  350. j = portion(p.y, w->r.min.y, w->r.max.y);
  351. return 3*j+i;
  352. }
  353. void
  354. cornercursor(Window *w, Point p, int force)
  355. {
  356. if(w!=nil && winborder(w, p))
  357. jaysetcursor(corners[whichcorner(w, p)], force);
  358. else
  359. wsetcursor(w, force);
  360. }
  361. /* thread to allow fsysproc to synchronize window closing with main proc */
  362. void
  363. winclosethread(void* v)
  364. {
  365. Window *w;
  366. threadsetname("winclosethread");
  367. for(;;){
  368. w = recvp(winclosechan);
  369. wclose(w);
  370. }
  371. }
  372. /* thread to make Deleted windows that the client still holds disappear offscreen after an interval */
  373. void
  374. deletethread(void* v)
  375. {
  376. char *s, namet[32 + 6]; //32(w->name) + 6(.title)
  377. Image *i, *t;
  378. threadsetname("deletethread");
  379. for(;;){
  380. s = recvp(deletechan);
  381. i = namedimage(display, s);
  382. sprint(namet, "%s.title", s);
  383. t = namedimage(display, namet);
  384. if(i != nil){
  385. /* move it off-screen to hide it, since client is slow in letting it go */
  386. originwindow(i, i->r.min, view->r.max);
  387. }
  388. freeimage(i);
  389. if(t != nil){
  390. /* move it off-screen to hide it, since client is slow in letting it go */
  391. originwindow(t, t->r.min, view->r.max);
  392. }
  393. freeimage(t);
  394. free(s);
  395. }
  396. }
  397. void
  398. deletetimeoutproc(void *v)
  399. {
  400. char *s;
  401. s = v;
  402. sleep(750); /* remove window from screen after 3/4 of a second */
  403. sendp(deletechan, s);
  404. }
  405. /*
  406. * Button 6 - keyboard toggle - has been pressed.
  407. * Send event to keyboard, wait for button up, send that.
  408. * Note: there is no coordinate translation done here; this
  409. * is just about getting button 6 to the keyboard simulator.
  410. */
  411. void
  412. keyboardhide(void)
  413. {
  414. send(wkeyboard->mc.c, mouse);
  415. do
  416. readmouse(mousectl);
  417. while(mouse->buttons & (1<<5));
  418. send(wkeyboard->mc.c, mouse);
  419. }
  420. void
  421. mousethread(void* v)
  422. {
  423. int sending, inside, scrolling, moving, band;
  424. Window *oin, *w, *winput;
  425. Image *i;
  426. Rectangle r;
  427. Point xy;
  428. Mouse tmp;
  429. enum {
  430. MReshape,
  431. MMouse,
  432. NALT
  433. };
  434. static Alt alts[NALT+1];
  435. threadsetname("mousethread");
  436. sending = FALSE;
  437. scrolling = FALSE;
  438. moving = FALSE;
  439. alts[MReshape].c = mousectl->resizec;
  440. alts[MReshape].v = nil;
  441. alts[MReshape].op = CHANRCV;
  442. alts[MMouse].c = mousectl->c;
  443. alts[MMouse].v = (Mouse *)mousectl;
  444. alts[MMouse].op = CHANRCV;
  445. alts[NALT].op = CHANEND;
  446. for(;;)
  447. switch(alt(alts)){
  448. case MReshape:
  449. resized();
  450. break;
  451. case MMouse:
  452. if(wkeyboard!=nil && (mouse->buttons & (1<<5))){
  453. keyboardhide();
  454. break;
  455. }
  456. Again:
  457. winput = input;
  458. /* override everything for the keyboard window */
  459. if(wkeyboard!=nil && ptinrect(mouse->xy, wkeyboard->screenr)){
  460. /* make sure it's on top; this call is free if it is */
  461. wtopme(wkeyboard);
  462. winput = wkeyboard;
  463. }
  464. if(ptinrect(mouse->xy, taskPanel->r) && mouse->buttons == 1){
  465. clickpanel(mouse->xy, taskPanel);
  466. goto Drain;
  467. }
  468. if(winput!=nil && winput->i!=nil){
  469. /* convert to logical coordinates */
  470. xy.x = mouse->xy.x + (winput->i->r.min.x-winput->screenr.min.x);
  471. xy.y = mouse->xy.y + (winput->i->r.min.y-winput->screenr.min.y);
  472. /* the up and down scroll buttons are not subject to the usual rules */
  473. if((mouse->buttons&(8|16)) && !winput->mouseopen)
  474. goto Sending;
  475. //inside = ptinrect(mouse->xy, insetrect(winput->screenr, Selborder));
  476. inside = ptinrect(mouse->xy, insetrect(winput->r, Selborder));
  477. if(winput->mouseopen)
  478. scrolling = FALSE;
  479. else if(scrolling)
  480. scrolling = mouse->buttons;
  481. else
  482. scrolling = mouse->buttons && ptinrect(xy, winput->scrollr);
  483. /* topped will be zero or less if window has been bottomed */
  484. if(sending == FALSE && !scrolling && winborder(winput, mouse->xy) && winput->topped>0){
  485. moving = TRUE;
  486. }else if (sending == FALSE && !scrolling && winput->isVisible && ptinrect(mouse->xy, insetrect(winput->t->r, Selborder)) && winput->topped>0 && mouse->buttons&1) {
  487. moving = TRUE;
  488. }else if(inside && (scrolling || winput->mouseopen || (mouse->buttons&1))){
  489. sending = TRUE;
  490. }
  491. }else
  492. sending = FALSE;
  493. if(sending){
  494. Sending:
  495. if(mouse->buttons == 0){
  496. cornercursor(winput, mouse->xy, 0);
  497. sending = FALSE;
  498. }else
  499. wsetcursor(winput, 0);
  500. tmp = *(Mouse *)mousectl;
  501. tmp.xy = xy;
  502. send(winput->mc.c, &tmp);
  503. continue;
  504. }
  505. w = wpointto(mouse->xy);
  506. /* change cursor if over anyone's border */
  507. if(w != nil)
  508. cornercursor(w, mouse->xy, 0);
  509. else
  510. jaysetcursor(nil, 0);
  511. if(moving && (mouse->buttons&7)){
  512. oin = winput;
  513. band = mouse->buttons & 3;
  514. sweeping = 1;
  515. if(winput->isVisible && ptinrect(mouse->xy, winput->bc)){
  516. whooverbutton(mouse->xy, winput);
  517. while(mouse->buttons){
  518. readmouse(mousectl);
  519. }
  520. if(ptinrect(mouse->xy, winput->bc)) // only delete if we are still in the red button
  521. wsendctlmesg(w, Deleted, ZR, nil);
  522. else
  523. whooverbutton(Pt(0,0), winput);
  524. w=nil;
  525. i=nil;
  526. } else if(winput->isVisible && ptinrect(mouse->xy, winput->bmax)) {
  527. whooverbutton(mouse->xy, winput);
  528. while(mouse->buttons){
  529. readmouse(mousectl);
  530. }
  531. if(ptinrect(mouse->xy, winput->bmax)){
  532. // Is the window maximized?
  533. if (winput->maximized){
  534. winput->maximized=0;
  535. //Restore size
  536. i = allocwindow(wscreen, windowMinusTitle(winput->originalr, winput->t), Refbackup, DWhite);
  537. }else{
  538. winput->originalr = winput->r;
  539. winput->maximized=1;
  540. i = allocwindow(wscreen, windowMinusTitle(windowspace, winput->t), Refbackup, DWhite);
  541. }
  542. }else {
  543. whooverbutton(Pt(0,0), winput);
  544. i=nil;
  545. }
  546. } else if (winput->isVisible && ptinrect(mouse->xy, winput->bmin)) {
  547. whooverbutton(mouse->xy, winput);
  548. while(mouse->buttons){
  549. readmouse(mousectl);
  550. }
  551. if (ptinrect(mouse->xy, winput->bmin)){
  552. whide(winput);
  553. w=nil;
  554. } else {
  555. whooverbutton(Pt(0,0), winput);
  556. }
  557. i=nil;
  558. } else if(winput->isVisible && ptinrect(mouse->xy, insetrect(winput->t->r, Selborder))){ //Moving pressing left button on title bar
  559. i = drag(winput, &r);
  560. band = 0;
  561. }
  562. else if(band) //Resize
  563. i = bandsize(winput);
  564. else //Move
  565. i = drag(winput, &r);
  566. sweeping = 0;
  567. if(i != nil){
  568. if(winput == oin){
  569. if(band){
  570. wsendctlmesg(winput, Reshaped, i->r, i);
  571. }
  572. else
  573. wsendctlmesg(winput, Moved, r, i);
  574. cornercursor(winput, mouse->xy, 1);
  575. }else
  576. freeimage(i);
  577. }
  578. }
  579. if(w != nil)
  580. cornercursor(w, mouse->xy, 0);
  581. /* we're not sending the event, but if button is down maybe we should */
  582. if(mouse->buttons){
  583. /* w->topped will be zero or less if window has been bottomed */
  584. if(w==nil || (w==winput && w->topped>0)){
  585. if(mouse->buttons & 1){
  586. ;
  587. }else if(mouse->buttons & 2){
  588. if(winput && !winput->mouseopen)
  589. button2menu(winput);
  590. }else if(mouse->buttons & 4)
  591. button3menu();
  592. }else{
  593. /* if button 1 event in the window, top the window and wait for button up. */
  594. /* otherwise, top the window and pass the event on */
  595. if(wtop(mouse->xy) && (mouse->buttons!=1 || winborder(w, mouse->xy)))
  596. goto Again;
  597. goto Drain;
  598. }
  599. }
  600. moving = FALSE;
  601. break;
  602. Drain:
  603. do
  604. readmouse(mousectl);
  605. while(mousectl->buttons);
  606. moving = FALSE;
  607. goto Again; /* recalculate mouse position, cursor */
  608. }
  609. }
  610. void
  611. resized(void)
  612. {
  613. Image *im;
  614. int i, j, ishidden;
  615. Rectangle r;
  616. Point o, n;
  617. Window *w;
  618. if(getwindow(display, Refnone) < 0)
  619. error("failed to re-attach window");
  620. freescrtemps();
  621. view = screen;
  622. freescreen(wscreen);
  623. iconreinit();
  624. wscreen = allocscreen(screen, background, 0);
  625. if(wscreen == nil)
  626. error("can't re-allocate screen");
  627. draw(view, view->r, background, nil, view->r.min);
  628. redrawpanel();
  629. o = subpt(viewr.max, viewr.min);
  630. n = subpt(view->clipr.max, view->clipr.min);
  631. for(i=0; i<nwindow; i++){
  632. w = window[i];
  633. if(w->deleted)
  634. continue;
  635. if(w->maximized){
  636. r = windowMinusTitle(windowspace, w->t);
  637. w->originalr = rectsubpt(w->originalr, viewr.min);
  638. w->originalr.min.x = (w->originalr.min.x*n.x)/o.x;
  639. w->originalr.min.y = (w->originalr.min.y*n.y)/o.y;
  640. w->originalr.max.x = (w->originalr.max.x*n.x)/o.x;
  641. w->originalr.max.y = (w->originalr.max.y*n.y)/o.y;
  642. w->originalr = rectaddpt(w->originalr, screen->clipr.min);
  643. } else {
  644. r = rectsubpt(w->r, viewr.min);
  645. r.min.x = (r.min.x*n.x)/o.x;
  646. r.min.y = (r.min.y*n.y)/o.y;
  647. r.max.x = (r.max.x*n.x)/o.x;
  648. r.max.y = (r.max.y*n.y)/o.y;
  649. r = rectaddpt(r, screen->clipr.min);
  650. }
  651. ishidden = 0;
  652. for(j=0; j<nhidden; j++)
  653. if(w == hidden[j]){
  654. ishidden = 1;
  655. break;
  656. }
  657. if(ishidden){
  658. im = allocimage(display, r, screen->chan, 0, DWhite);
  659. r = ZR;
  660. }else
  661. im = allocwindow(wscreen, r, Refbackup, DWhite);
  662. if(im)
  663. wsendctlmesg(w, Reshaped, r, im);
  664. }
  665. viewr = screen->r;
  666. flushimage(display, 1);
  667. }
  668. void jayredraw(void){
  669. resized();
  670. }
  671. void
  672. button3menu(void)
  673. {
  674. int i;
  675. for(i=0; i<nhidden; i++)
  676. menu3str[i+Hidden] = hidden[i]->label;
  677. menu3str[i+Hidden] = nil;
  678. sweeping = 1;
  679. switch(i = menuhit(3, mousectl, &menu3, wscreen)){
  680. case -1:
  681. break;
  682. case New:
  683. new(sweep(), FALSE, scrolling, 0, nil, "/bin/rc", nil);
  684. break;
  685. case Reshape:
  686. resize();
  687. break;
  688. case Move:
  689. move();
  690. break;
  691. case Delete:
  692. delete();
  693. break;
  694. case Hide:
  695. hide();
  696. break;
  697. case Exit:
  698. if(Hidden > Exit){
  699. send(exitchan, nil);
  700. break;
  701. }
  702. /* else fall through */
  703. default:
  704. unhide(i);
  705. break;
  706. }
  707. sweeping = 0;
  708. }
  709. void
  710. button2menu(Window *w)
  711. {
  712. if(w->deleted)
  713. return;
  714. incref(&w->Ref);
  715. if(w->scrolling)
  716. menu2str[Scroll] = "noscroll";
  717. else
  718. menu2str[Scroll] = "scroll";
  719. switch(menuhit(2, mousectl, &menu2, wscreen)){
  720. case Cut:
  721. wsnarf(w);
  722. wcut(w);
  723. wscrdraw(w);
  724. break;
  725. case Snarf:
  726. wsnarf(w);
  727. break;
  728. case Paste:
  729. getsnarf();
  730. wpaste(w);
  731. wscrdraw(w);
  732. break;
  733. case Plumb:
  734. wplumb(w);
  735. break;
  736. case Send:
  737. getsnarf();
  738. wsnarf(w);
  739. if(nsnarf == 0)
  740. break;
  741. if(w->rawing){
  742. waddraw(w, snarf, nsnarf);
  743. if(snarf[nsnarf-1]!='\n' && snarf[nsnarf-1]!='\004')
  744. {
  745. Rune newline[] = { '\n' };
  746. waddraw(w, newline, 1);
  747. }
  748. }else{
  749. winsert(w, snarf, nsnarf, w->nr);
  750. if(snarf[nsnarf-1]!='\n' && snarf[nsnarf-1]!='\004')
  751. {
  752. Rune newline[] = { '\n' };
  753. winsert(w, newline, 1, w->nr);
  754. }
  755. }
  756. wsetselect(w, w->nr, w->nr);
  757. wshow(w, w->nr);
  758. break;
  759. case Scroll:
  760. if(w->scrolling ^= 1)
  761. wshow(w, w->nr);
  762. break;
  763. }
  764. wclose(w);
  765. wsendctlmesg(w, Wakeup, ZR, nil);
  766. flushimage(display, 1);
  767. }
  768. Point
  769. onscreen(Point p)
  770. {
  771. p.x = max(screen->clipr.min.x, p.x);
  772. p.x = min(screen->clipr.max.x, p.x);
  773. p.y = max(screen->clipr.min.y, p.y);
  774. p.y = min(screen->clipr.max.y, p.y);
  775. return p;
  776. }
  777. Image*
  778. sweep(void)
  779. {
  780. Image *i, *oi;
  781. Rectangle r;
  782. Point p0, p;
  783. i = nil;
  784. menuing = TRUE;
  785. jaysetcursor(&crosscursor, 1);
  786. while(mouse->buttons == 0)
  787. readmouse(mousectl);
  788. p0 = onscreen(mouse->xy);
  789. p = p0;
  790. r.min = p;
  791. r.max = p;
  792. oi = nil;
  793. while(mouse->buttons == 4){
  794. readmouse(mousectl);
  795. if(mouse->buttons != 4 && mouse->buttons != 0)
  796. break;
  797. if(!eqpt(mouse->xy, p)){
  798. p = onscreen(mouse->xy);
  799. r = canonrect(Rpt(p0, p));
  800. if(Dx(r)>5 && Dy(r)>5){
  801. i = allocwindow(wscreen, r, Refnone, 0xEEEEEEFF); /* grey */
  802. freeimage(oi);
  803. if(i == nil)
  804. goto Rescue;
  805. oi = i;
  806. //border for click and drag a new window
  807. border(i, r, Selborder, red, ZP);
  808. flushimage(display, 1);
  809. }
  810. }
  811. }
  812. if(mouse->buttons != 0)
  813. goto Rescue;
  814. if(i==nil || Dx(i->r)<100 || Dy(i->r)<3*font->height)
  815. goto Rescue;
  816. oi = i;
  817. i = allocwindow(wscreen, oi->r, Refbackup, DWhite);
  818. freeimage(oi);
  819. if(i == nil)
  820. goto Rescue;
  821. //border(i, r, Selborder, red, ZP);
  822. cornercursor(input, mouse->xy, 1);
  823. goto Return;
  824. Rescue:
  825. freeimage(i);
  826. i = nil;
  827. cornercursor(input, mouse->xy, 1);
  828. while(mouse->buttons)
  829. readmouse(mousectl);
  830. Return:
  831. moveto(mousectl, mouse->xy); /* force cursor update; ugly */
  832. menuing = FALSE;
  833. return i;
  834. }
  835. void
  836. drawedge(Image **bp, Rectangle r)
  837. {
  838. Image *b = *bp;
  839. if(b != nil && Dx(b->r) == Dx(r) && Dy(b->r) == Dy(r))
  840. originwindow(b, r.min, r.min);
  841. else{
  842. freeimage(b);
  843. *bp = allocwindow(wscreen, r, Refbackup, DRed);
  844. }
  845. }
  846. void
  847. drawborder(Rectangle r, int show)
  848. {
  849. static Image *b[4];
  850. int i;
  851. if(show == 0){
  852. for(i = 0; i < 4; i++){
  853. freeimage(b[i]);
  854. b[i] = nil;
  855. }
  856. }else{
  857. r = canonrect(r);
  858. drawedge(&b[0], Rect(r.min.x, r.min.y, r.min.x+Borderwidth, r.max.y));
  859. drawedge(&b[1], Rect(r.min.x+Borderwidth, r.min.y, r.max.x-Borderwidth, r.min.y+Borderwidth));
  860. drawedge(&b[2], Rect(r.max.x-Borderwidth, r.min.y, r.max.x, r.max.y));
  861. drawedge(&b[3], Rect(r.min.x+Borderwidth, r.max.y-Borderwidth, r.max.x-Borderwidth, r.max.y));
  862. }
  863. }
  864. Image*
  865. drag(Window *w, Rectangle *rp)
  866. {
  867. Image *ni;
  868. Point p, op, d, dm, om;
  869. Rectangle r;
  870. menuing = TRUE;
  871. om = mouse->xy;
  872. jaysetcursor(&boxcursor, 1);
  873. //dm = subpt(mouse->xy, w->screenr.min);
  874. //d = subpt(i->r.max, i->r.min);
  875. dm = subpt(mouse->xy, w->r.min);
  876. d = subpt(w->r.max, w->r.min);
  877. op = subpt(mouse->xy, dm);
  878. drawborder(Rect(op.x, op.y, op.x+d.x, op.y+d.y), 1);
  879. flushimage(display, 1);
  880. while(mouse->buttons == 4 || mouse->buttons == 1){
  881. p = subpt(mouse->xy, dm);
  882. r = Rect(p.x, p.y, p.x+d.x, p.y+d.y);
  883. //if(!ptinrect(p, taskPanel->r) && !ptinrect(mouse->xy, taskPanel->r))
  884. if(ptinrect(p, windowspace) && ptinrect(mouse->xy, windowspace))
  885. //if(rectinrect(r, windowspace)){
  886. if(!eqpt(p, op)){
  887. drawborder(r, 1);
  888. flushimage(display, 1);
  889. op = p;
  890. }
  891. readmouse(mousectl);
  892. }
  893. r = Rect(op.x, op.y, op.x+d.x, op.y+d.y);
  894. drawborder(r, 0);
  895. cornercursor(w, mouse->xy, 1);
  896. moveto(mousectl, mouse->xy); /* force cursor update; ugly */
  897. menuing = FALSE;
  898. flushimage(display, 1);
  899. r = windowMinusTitle(r, w->t);
  900. if(mouse->buttons!=0 || (ni=allocwindow(wscreen, r, Refbackup, DWhite))==nil){
  901. moveto(mousectl, om);
  902. while(mouse->buttons)
  903. readmouse(mousectl);
  904. *rp = Rect(0, 0, 0, 0);
  905. return nil;
  906. }
  907. //i = w->i;
  908. //draw(ni, ni->r, i, nil, i->r.min);
  909. *rp = r;
  910. return ni;
  911. }
  912. Point
  913. cornerpt(Rectangle r, Point p, int which)
  914. {
  915. switch(which){
  916. case 0: /* top left */
  917. p = Pt(r.min.x, r.min.y);
  918. break;
  919. case 2: /* top right */
  920. p = Pt(r.max.x,r.min.y);
  921. break;
  922. case 6: /* bottom left */
  923. p = Pt(r.min.x, r.max.y);
  924. break;
  925. case 8: /* bottom right */
  926. p = Pt(r.max.x, r.max.y);
  927. break;
  928. case 1: /* top edge */
  929. p = Pt(p.x,r.min.y);
  930. break;
  931. case 5: /* right edge */
  932. p = Pt(r.max.x, p.y);
  933. break;
  934. case 7: /* bottom edge */
  935. p = Pt(p.x, r.max.y);
  936. break;
  937. case 3: /* left edge */
  938. p = Pt(r.min.x, p.y);
  939. break;
  940. }
  941. return p;
  942. }
  943. Rectangle
  944. whichrect(Rectangle r, Point p, int which)
  945. {
  946. switch(which){
  947. case 0: /* top left */
  948. r = Rect(p.x, p.y, r.max.x, r.max.y);
  949. break;
  950. case 2: /* top right */
  951. r = Rect(r.min.x, p.y, p.x, r.max.y);
  952. break;
  953. case 6: /* bottom left */
  954. r = Rect(p.x, r.min.y, r.max.x, p.y);
  955. break;
  956. case 8: /* bottom right */
  957. r = Rect(r.min.x, r.min.y, p.x, p.y);
  958. break;
  959. case 1: /* top edge */
  960. r = Rect(r.min.x, p.y, r.max.x, r.max.y);
  961. break;
  962. case 5: /* right edge */
  963. r = Rect(r.min.x, r.min.y, p.x, r.max.y);
  964. break;
  965. case 7: /* bottom edge */
  966. r = Rect(r.min.x, r.min.y, r.max.x, p.y);
  967. break;
  968. case 3: /* left edge */
  969. r = Rect(p.x, r.min.y, r.max.x, r.max.y);
  970. break;
  971. }
  972. return canonrect(r);
  973. }
  974. Image*
  975. bandsize(Window *w)
  976. {
  977. Image *i;
  978. Rectangle r, or;
  979. Point p, startp;
  980. int which, but;
  981. p = mouse->xy;
  982. but = mouse->buttons;
  983. which = whichcorner(w, p);
  984. p = cornerpt(w->r, p, which);
  985. wmovemouse(w, p);
  986. readmouse(mousectl);
  987. r = whichrect(w->r, p, which);
  988. drawborder(r, 1);
  989. or = r;
  990. startp = p;
  991. while(mouse->buttons == but){
  992. p = onscreen(mouse->xy);
  993. r = whichrect(w->r, p, which);
  994. if(!eqrect(r, or) && goodrect(r)){
  995. drawborder(r, 1);
  996. flushimage(display, 1);
  997. or = r;
  998. }
  999. readmouse(mousectl);
  1000. }
  1001. p = mouse->xy;
  1002. drawborder(or, 0);
  1003. flushimage(display, 1);
  1004. wsetcursor(w, 1);
  1005. if(mouse->buttons!=0 || Dx(or)<100 || Dy(or)<3*font->height){
  1006. while(mouse->buttons)
  1007. readmouse(mousectl);
  1008. return nil;
  1009. }
  1010. if(abs(p.x-startp.x)+abs(p.y-startp.y) <= 1)
  1011. return nil;
  1012. or = windowMinusTitle(or, w->t);
  1013. i = allocwindow(wscreen, or, Refbackup, DWhite);
  1014. if(i == nil)
  1015. return nil;
  1016. border(i, r, Selborder, red, ZP);
  1017. return i;
  1018. }
  1019. Window*
  1020. pointto(int wait)
  1021. {
  1022. Window *w;
  1023. menuing = TRUE;
  1024. jaysetcursor(&sightcursor, 1);
  1025. while(mouse->buttons == 0)
  1026. readmouse(mousectl);
  1027. if(mouse->buttons == 4)
  1028. w = wpointto(mouse->xy);
  1029. else
  1030. w = nil;
  1031. if(wait){
  1032. while(mouse->buttons){
  1033. if(mouse->buttons!=4 && w !=nil){ /* cancel */
  1034. cornercursor(input, mouse->xy, 0);
  1035. w = nil;
  1036. }
  1037. readmouse(mousectl);
  1038. }
  1039. if(w != nil && wpointto(mouse->xy) != w)
  1040. w = nil;
  1041. }
  1042. cornercursor(input, mouse->xy, 0);
  1043. moveto(mousectl, mouse->xy); /* force cursor update; ugly */
  1044. menuing = FALSE;
  1045. return w;
  1046. }
  1047. void
  1048. delete(void)
  1049. {
  1050. Window *w;
  1051. w = pointto(TRUE);
  1052. if(w)
  1053. wsendctlmesg(w, Deleted, ZR, nil);
  1054. }
  1055. void
  1056. resize(void)
  1057. {
  1058. Window *w;
  1059. Image *i;
  1060. w = pointto(TRUE);
  1061. if(w == nil)
  1062. return;
  1063. i = sweep();
  1064. if(i)
  1065. wsendctlmesg(w, Reshaped, i->r, i);
  1066. }
  1067. void
  1068. move(void)
  1069. {
  1070. Window *w;
  1071. Image *i;
  1072. Rectangle r;
  1073. w = pointto(FALSE);
  1074. if(w == nil)
  1075. return;
  1076. i = drag(w, &r);
  1077. if(i)
  1078. wsendctlmesg(w, Moved, r, i);
  1079. cornercursor(input, mouse->xy, 1);
  1080. }
  1081. int
  1082. whide(Window *w)
  1083. {
  1084. Image *i;
  1085. int j;
  1086. for(j=0; j<nhidden; j++)
  1087. if(hidden[j] == w) /* already hidden */
  1088. return -1;
  1089. i = allocimage(display, w->screenr, w->i->chan, 0, DWhite);
  1090. if(i){
  1091. hidden[nhidden++] = w;
  1092. wsendctlmesg(w, Reshaped, ZR, i);
  1093. w->isVisible = 0;
  1094. wcurrentnext();
  1095. wbottomme(w);
  1096. return 1;
  1097. }
  1098. return 0;
  1099. }
  1100. int
  1101. wunhide(int h)
  1102. {
  1103. Image *i;
  1104. Window *w;
  1105. w = hidden[h];
  1106. i = allocwindow(wscreen, w->i->r, Refbackup, DWhite);
  1107. if(i){
  1108. --nhidden;
  1109. memmove(hidden+h, hidden+h+1, (nhidden-h)*sizeof(Window*));
  1110. wsendctlmesg(w, Reshaped, w->i->r, i);
  1111. w->isVisible=1;
  1112. return 1;
  1113. }
  1114. return 0;
  1115. }
  1116. void
  1117. hide(void)
  1118. {
  1119. Window *w;
  1120. w = pointto(TRUE);
  1121. if(w == nil)
  1122. return;
  1123. whide(w);
  1124. }
  1125. void
  1126. unhide(int h)
  1127. {
  1128. Window *w;
  1129. h -= Hidden;
  1130. w = hidden[h];
  1131. if(w == nil)
  1132. return;
  1133. wunhide(h);
  1134. }
  1135. Window*
  1136. new(Image *i, int hideit, int scrollit, int pid, char *dir, char *cmd,
  1137. char **argv)
  1138. {
  1139. Window *w;
  1140. Mousectl *mc;
  1141. Channel *cm, *ck, *cctl, *cpid;
  1142. void **arg;
  1143. if(i == nil)
  1144. return nil;
  1145. cm = chancreate(sizeof(Mouse), 0);
  1146. ck = chancreate(sizeof(Rune*), 0);
  1147. cctl = chancreate(sizeof(Wctlmesg), 4);
  1148. cpid = chancreate(sizeof(int), 0);
  1149. if(cm==nil || ck==nil || cctl==nil)
  1150. error("new: channel alloc failed");
  1151. mc = emalloc(sizeof(Mousectl));
  1152. *mc = *mousectl;
  1153. mc->image = i;
  1154. mc->c = cm;
  1155. w = wmk(i, mc, ck, cctl, scrollit);
  1156. free(mc); /* wmk copies *mc */
  1157. window = erealloc(window, ++nwindow*sizeof(Window*));
  1158. window[nwindow-1] = w;
  1159. w->isVisible=!hideit;
  1160. if(hideit){
  1161. hidden[nhidden++] = w;
  1162. w->screenr = ZR;
  1163. w->r = ZR;
  1164. }
  1165. threadcreate(winctl, w, 8192);
  1166. if(!hideit)
  1167. wcurrent(w);
  1168. flushimage(display, 1);
  1169. if(pid == 0){
  1170. arg = emalloc(5*sizeof(void*));
  1171. arg[0] = w;
  1172. arg[1] = cpid;
  1173. arg[2] = cmd;
  1174. if(argv == nil)
  1175. arg[3] = rcargv;
  1176. else
  1177. arg[3] = argv;
  1178. arg[4] = dir;
  1179. proccreate(winshell, arg, 8192);
  1180. pid = recvul(cpid);
  1181. free(arg);
  1182. }
  1183. if(pid == 0){
  1184. /* window creation failed */
  1185. wsendctlmesg(w, Deleted, ZR, nil);
  1186. chanfree(cpid);
  1187. return nil;
  1188. }
  1189. wsetpid(w, pid, 1);
  1190. wsetname(w);
  1191. if(dir)
  1192. w->dir = estrdup(dir);
  1193. chanfree(cpid);
  1194. Image *wis = winspace(w);
  1195. if (wis != nil){
  1196. wresize(w, wis, 1);
  1197. }
  1198. return w;
  1199. }