screen.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. /*
  2. * ti omap35 display subsystem (dss)
  3. *
  4. * can handle 2ⁿ bits per pixel for 0 < n ≤ 4, and 12 and 24 bits.
  5. * can handle 1024×768 at 60 Hz with pixel clock of 63.5 MHz
  6. * 1280×800 at 59.91 Hz with pixel clock of 71 MHz
  7. * 1400×1050 lcd at 50 MHz with pixel clock of 75 MHz
  8. * has 256 24-bit entries in RGB palette
  9. */
  10. #include "u.h"
  11. #include "../port/lib.h"
  12. #include "mem.h"
  13. #include "dat.h"
  14. #include "fns.h"
  15. #include "io.h"
  16. #include "ureg.h"
  17. #include "../port/error.h"
  18. #define Image IMAGE
  19. #include <draw.h>
  20. #include <memdraw.h>
  21. #include <cursor.h>
  22. #include "screen.h"
  23. // #include "gamma.h"
  24. enum {
  25. Tabstop = 4, /* should be 8 */
  26. Scroll = 8, /* lines to scroll at one time */
  27. /*
  28. * screen settings for Wid and Ht, should a bit more dynamic?
  29. * http://www.epanorama.net/faq/vga2rgb/calc.html
  30. * used to calculate settings.
  31. */
  32. // Hbp = (248-1) << 20,
  33. // Hfp = (48-1) << 8,
  34. // Hsw = 112-1,
  35. // Vbp = 38 << 20,
  36. // Vfp = 1 << 8,
  37. // Vsw = 3,
  38. Tft = 0x60,
  39. Loadmode = 2 << 1,
  40. Fifosize = 0x400,
  41. /* dispc sysconfig */
  42. Midlemode = 2 << 12,
  43. Sidlemode = 2 << 3,
  44. EnableWakeup = 1 << 2,
  45. Autoidle = 1 << 0,
  46. /* dispc pool_freq */
  47. Ipc = 1 << 14,
  48. Ihs = 1 << 13,
  49. Ivs = 1 << 12,
  50. Acb = 0x28,
  51. /* gfx attribs */
  52. Burstsize = 2 << 6,
  53. Format = 6 << 1,
  54. Gfxenable = 1 << 0,
  55. /* dispc control */
  56. Gpout1 = 1 << 16,
  57. Gpout0 = 1 << 15,
  58. Tftdata = 3 << 8,
  59. Digital = 1 << 6,
  60. Lcd = 1 << 5,
  61. Stntft = 1 << 3,
  62. Digitalen = 1 << 1,
  63. // Lcden = 1 << 0, /* unused */
  64. };
  65. typedef struct Dispcregs Dispc;
  66. typedef struct Dssregs Dss;
  67. typedef struct Ioregs Ioregs;
  68. struct Ioregs { /* common registers, 68 (0x44) bytes */
  69. ulong rev;
  70. uchar _pad0[0x10-0x4];
  71. ulong sysconf;
  72. ulong sysstat;
  73. ulong irqstat1;
  74. /* Dispc only regs */
  75. ulong irqen1;
  76. ulong wkupen;
  77. ulong _pad1;
  78. ulong irqsts2;
  79. ulong irqen2;
  80. ulong _pad2[4];
  81. ulong ctrl;
  82. };
  83. struct Dssregs { /* display subsys at 0x48050000 */
  84. Ioregs;
  85. ulong sdicrtl;
  86. ulong pllcrtl;
  87. uchar _pad3[0x5c-0x4c];
  88. ulong sdistat;
  89. };
  90. struct Dispcregs { /* display ctlr at 0x48050400 */
  91. Ioregs;
  92. ulong config;
  93. ulong _pad3;
  94. ulong defaultcolor[2];
  95. ulong transcolor[2];
  96. ulong linestat;
  97. ulong linenum;
  98. ulong timing_h;
  99. ulong timing_v;
  100. ulong pol_req;
  101. ulong divisor;
  102. ulong alpha;
  103. ulong digsize;
  104. ulong lcdsize;
  105. ulong base[2]; /* should allocate both to avoid dithering */
  106. ulong pos;
  107. ulong size;
  108. ulong _pad4[4];
  109. ulong attrib;
  110. ulong fifothr;
  111. ulong fifosize;
  112. ulong rowinc;
  113. ulong pixelinc;
  114. ulong winskip;
  115. ulong palette; /* gfx_table_ba */
  116. uchar _pad5[0x5d4 - 0x4bc];
  117. ulong datacycle[3];
  118. uchar _pad5[0x620 - 0x5e0];
  119. ulong cprcoefr;
  120. ulong cprcoefg;
  121. ulong cprcoefb;
  122. ulong preload;
  123. };
  124. int drawdebug;
  125. Point ZP = {0, 0};
  126. Cursor arrow = {
  127. { -1, -1 },
  128. { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
  129. 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
  130. 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
  131. 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
  132. },
  133. { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
  134. 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
  135. 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
  136. 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
  137. },
  138. };
  139. OScreen oscreen;
  140. Settings settings[] = {
  141. [Res800x600] { 800, 600, 60, RGB16, 40000, 88, 40, 128, 23, 1, 5, },
  142. [Res1024x768] { 1024, 768, 60, RGB16, 65000, 160, 24, 136, 29, 3, 7, },
  143. [Res1280x1024] { 1280, 1024, 60, RGB16, 108000, 248, 48, 112, 38, 1, 4, },
  144. [Res1400x1050] { 1400, 1050, 50, RGB16, 108000, 248, 48, 112, 38, 1, 4, }, // TODO
  145. };
  146. Omap3fb *framebuf;
  147. Memimage *gscreen;
  148. static Memdata xgdata;
  149. static Memimage xgscreen =
  150. {
  151. { 0, 0, Wid, Ht }, /* r */
  152. { 0, 0, Wid, Ht }, /* clipr */
  153. Depth, /* depth */
  154. 3, /* nchan */
  155. RGB16, /* chan */
  156. nil, /* cmap */
  157. &xgdata, /* data */
  158. 0, /* zero */
  159. Wid*(Depth/BI2BY)/BY2WD, /* width in words of a single scan line */
  160. 0, /* layer */
  161. 0, /* flags */
  162. };
  163. static Memimage *conscol;
  164. static Memimage *back;
  165. static Memsubfont *memdefont;
  166. static Lock screenlock;
  167. static Point curpos;
  168. static int h, w;
  169. static int landscape = 0; /* screen orientation, default is 0: portrait */
  170. static ushort *vscreen; /* virtual screen */
  171. static Rectangle window;
  172. static Dispc *dispc = (Dispc *)PHYSDISPC;
  173. static Dss *dss = (Dss *)PHYSDSS;
  174. static void omapscreenputs(char *s, int n);
  175. static ulong rep(ulong, int);
  176. static void screenputc(char *buf);
  177. static void screenwin(void);
  178. /*
  179. * Software cursor.
  180. */
  181. int swvisible; /* is the cursor visible? */
  182. int swenabled; /* is the cursor supposed to be on the screen? */
  183. Memimage* swback; /* screen under cursor */
  184. Memimage* swimg; /* cursor image */
  185. Memimage* swmask; /* cursor mask */
  186. Memimage* swimg1;
  187. Memimage* swmask1;
  188. Point swoffset;
  189. Rectangle swrect; /* screen rectangle in swback */
  190. Point swpt; /* desired cursor location */
  191. Point swvispt; /* actual cursor location */
  192. int swvers; /* incremented each time cursor image changes */
  193. int swvisvers; /* the version on the screen */
  194. static void
  195. lcdoff(void)
  196. {
  197. dispc->ctrl &= ~1; /* disable the lcd */
  198. coherence();
  199. dispc->irqstat1 |= 1; /* set framedone */
  200. coherence();
  201. /* the lcd never comes ready, so don't bother with this */
  202. #ifdef notdef
  203. /* spin until the frame is complete, but not forever */
  204. for(cnt = 50; !(dispc->irqstat1 & 1) && cnt-- > 0; )
  205. delay(10);
  206. #endif
  207. delay(20); /* worst case for 1 frame, 50Hz */
  208. }
  209. static void
  210. dssstart(void)
  211. {
  212. /* should reset the dss system */
  213. dss->sysconf |= 1;
  214. coherence();
  215. }
  216. /* see spruf98i §15.6.7.4.2 */
  217. static void
  218. configdispc(void)
  219. {
  220. Settings *sp;
  221. sp = oscreen.settings;
  222. dss->ctrl &= 0x78; /* choose dss clock */
  223. dispc->sysconf = Midlemode | Sidlemode | EnableWakeup | Autoidle;
  224. dispc->config = Loadmode;
  225. coherence();
  226. /* pll */
  227. dispc->defaultcolor[0] = 0; /* set background color to black? */
  228. dispc->defaultcolor[1] = 0;
  229. dispc->transcolor[0] = 0; /* set transparency to full */
  230. dispc->transcolor[1] = 0;
  231. dispc->timing_h = (sp->hbp-1) << 20 | (sp->hfp-1) << 8 |
  232. (sp->hsw-1);
  233. dispc->timing_v = sp->vbp << 20 | sp->vfp << 8 |
  234. (sp->vsw-1);
  235. dispc->pol_req = Ipc | Ihs | Ivs | Acb;
  236. dispc->divisor = 1 << 16 | HOWMANY(432000, sp->pixelclock);
  237. dispc->lcdsize = (sp->ht - 1) << 16 | (sp->wid - 1);
  238. coherence();
  239. dispc->base[0] = PADDR(framebuf->pixel);
  240. dispc->base[1] = PADDR(framebuf->pixel);
  241. dispc->pos = 0; /* place screen in the left corner */
  242. /* use the whole screen */
  243. dispc->size = (sp->ht - 1) << 16 | (sp->wid - 1);
  244. /* what mode does plan 9 use for fb? */
  245. dispc->attrib = Burstsize | Format | Gfxenable;
  246. dispc->preload = Tft;
  247. dispc->fifosize = Fifosize;
  248. /* 1008 is max for our Burstsize */
  249. dispc->fifothr = (Fifosize - 1) << 16 | (1008 - 1);
  250. /* 1 byte is one pixel (not true, we use 2 bytes per pixel) */
  251. dispc->rowinc = 1;
  252. dispc->pixelinc = 1;
  253. dispc->winskip = 0; /* don't skip anything */
  254. coherence();
  255. // dispc->palette = PADDR(framebuf->palette);
  256. }
  257. static void
  258. lcdon(int enable)
  259. {
  260. dispc->ctrl = Gpout1 | Gpout0 | Tftdata | Digital | Lcd | Stntft |
  261. Digitalen | enable;
  262. coherence();
  263. delay(10);
  264. }
  265. static void
  266. lcdstop(void)
  267. {
  268. configscreengpio();
  269. screenclockson();
  270. lcdoff();
  271. }
  272. static void
  273. lcdinit(void)
  274. {
  275. lcdstop();
  276. dssstart();
  277. configdispc();
  278. }
  279. /* Paint the image data with blue pixels */
  280. void
  281. screentest(void)
  282. {
  283. int i;
  284. for (i = nelem(framebuf->pixel) - 1; i >= 0; i--)
  285. framebuf->pixel[i] = 0x1f; /* blue */
  286. // memset(framebuf->pixel, ~0, sizeof framebuf->pixel); /* white */
  287. }
  288. void
  289. screenpower(int on)
  290. {
  291. blankscreen(on == 0);
  292. }
  293. /*
  294. * called with drawlock locked for us, most of the time.
  295. * kernel prints at inopportune times might mean we don't
  296. * hold the lock, but memimagedraw is now reentrant so
  297. * that should be okay: worst case we get cursor droppings.
  298. */
  299. void
  300. swcursorhide(void)
  301. {
  302. if(swvisible == 0)
  303. return;
  304. if(swback == nil)
  305. return;
  306. swvisible = 0;
  307. memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
  308. flushmemscreen(swrect);
  309. }
  310. void
  311. swcursoravoid(Rectangle r)
  312. {
  313. if(swvisible && rectXrect(r, swrect))
  314. swcursorhide();
  315. }
  316. void
  317. swcursordraw(void)
  318. {
  319. if(swvisible)
  320. return;
  321. if(swenabled == 0)
  322. return;
  323. if(swback == nil || swimg1 == nil || swmask1 == nil)
  324. return;
  325. // assert(!canqlock(&drawlock)); // assertion fails on omap
  326. swvispt = swpt;
  327. swvisvers = swvers;
  328. swrect = rectaddpt(Rect(0,0,16,16), swvispt);
  329. memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
  330. memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
  331. flushmemscreen(swrect);
  332. swvisible = 1;
  333. }
  334. int
  335. cursoron(int dolock)
  336. {
  337. if (dolock)
  338. lock(&oscreen);
  339. cursoroff(0);
  340. swcursordraw();
  341. if (dolock)
  342. unlock(&oscreen);
  343. return 0;
  344. }
  345. void
  346. cursoroff(int dolock)
  347. {
  348. if (dolock)
  349. lock(&oscreen);
  350. swcursorhide();
  351. if (dolock)
  352. unlock(&oscreen);
  353. }
  354. void
  355. swload(Cursor *curs)
  356. {
  357. uchar *ip, *mp;
  358. int i, j, set, clr;
  359. if(!swimg || !swmask || !swimg1 || !swmask1)
  360. return;
  361. /*
  362. * Build cursor image and mask.
  363. * Image is just the usual cursor image
  364. * but mask is a transparent alpha mask.
  365. *
  366. * The 16x16x8 memimages do not have
  367. * padding at the end of their scan lines.
  368. */
  369. ip = byteaddr(swimg, ZP);
  370. mp = byteaddr(swmask, ZP);
  371. for(i=0; i<32; i++){
  372. set = curs->set[i];
  373. clr = curs->clr[i];
  374. for(j=0x80; j; j>>=1){
  375. *ip++ = set&j ? 0x00 : 0xFF;
  376. *mp++ = (clr|set)&j ? 0xFF : 0x00;
  377. }
  378. }
  379. swoffset = curs->offset;
  380. swvers++;
  381. memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
  382. memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
  383. }
  384. /* called from devmouse */
  385. void
  386. setcursor(Cursor* curs)
  387. {
  388. cursoroff(1);
  389. oscreen.Cursor = *curs;
  390. swload(curs);
  391. cursoron(1);
  392. }
  393. int
  394. swmove(Point p)
  395. {
  396. swpt = addpt(p, swoffset);
  397. return 0;
  398. }
  399. void
  400. swcursorclock(void)
  401. {
  402. int x;
  403. if(!swenabled)
  404. return;
  405. swmove(mousexy());
  406. if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
  407. return;
  408. x = splhi();
  409. if(swenabled)
  410. if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
  411. if(canqlock(&drawlock)){
  412. swcursorhide();
  413. swcursordraw();
  414. qunlock(&drawlock);
  415. }
  416. splx(x);
  417. }
  418. void
  419. swcursorinit(void)
  420. {
  421. static int init;
  422. if(!init){
  423. init = 1;
  424. addclock0link(swcursorclock, 10);
  425. }
  426. if(swback){
  427. freememimage(swback);
  428. freememimage(swmask);
  429. freememimage(swmask1);
  430. freememimage(swimg);
  431. freememimage(swimg1);
  432. }
  433. swback = allocmemimage(Rect(0,0,32,32), gscreen->chan);
  434. swmask = allocmemimage(Rect(0,0,16,16), GREY8);
  435. swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
  436. swimg = allocmemimage(Rect(0,0,16,16), GREY8);
  437. swimg1 = allocmemimage(Rect(0,0,16,16), GREY1);
  438. if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){
  439. print("software cursor: allocmemimage fails\n");
  440. return;
  441. }
  442. memfillcolor(swmask, DOpaque);
  443. memfillcolor(swmask1, DOpaque);
  444. memfillcolor(swimg, DBlack);
  445. memfillcolor(swimg1, DBlack);
  446. }
  447. /* called from main and possibly later from devdss to change resolution */
  448. void
  449. screeninit(void)
  450. {
  451. static int first = 1;
  452. if (first) {
  453. iprint("screeninit...");
  454. oscreen.settings = &settings[Res1280x1024];
  455. lcdstop();
  456. if (framebuf)
  457. free(framebuf);
  458. /* mode is 16*32 = 512 */
  459. framebuf = xspanalloc(sizeof *framebuf, 16*32, 0);
  460. }
  461. lcdinit();
  462. lcdon(1);
  463. if (first) {
  464. memimageinit();
  465. memdefont = getmemdefont();
  466. screentest();
  467. }
  468. xgdata.ref = 1;
  469. xgdata.bdata = (uchar *)framebuf->pixel;
  470. gscreen = &xgscreen;
  471. gscreen->r = Rect(0, 0, Wid, Ht);
  472. gscreen->clipr = gscreen->r;
  473. /* width, in words, of a single scan line */
  474. gscreen->width = Wid * (Depth / BI2BY) / BY2WD;
  475. flushmemscreen(gscreen->r);
  476. blanktime = 3; /* minutes */
  477. if (first) {
  478. iprint("on: blue for 3 seconds...");
  479. delay(3*1000);
  480. iprint("\n");
  481. screenwin(); /* draw border & top orange bar */
  482. screenputs = omapscreenputs;
  483. iprint("screen: frame buffer at %#p for %dx%d\n",
  484. framebuf, oscreen.settings->wid, oscreen.settings->ht);
  485. swenabled = 1;
  486. swcursorinit(); /* needs gscreen set */
  487. setcursor(&arrow);
  488. first = 0;
  489. }
  490. }
  491. /* flushmemscreen should change buffer? */
  492. void
  493. flushmemscreen(Rectangle r)
  494. {
  495. ulong start, end;
  496. if (r.min.x < 0)
  497. r.min.x = 0;
  498. if (r.max.x > Wid)
  499. r.max.x = Wid;
  500. if (r.min.y < 0)
  501. r.min.y = 0;
  502. if (r.max.y > Ht)
  503. r.max.y = Ht;
  504. if (rectclip(&r, gscreen->r) == 0)
  505. return;
  506. start = (ulong)&framebuf->pixel[r.min.y*Wid + r.min.x];
  507. end = (ulong)&framebuf->pixel[(r.max.y - 1)*Wid + r.max.x -1];
  508. cachedwbse((ulong *)start, end - start);
  509. }
  510. /*
  511. * export screen to devdraw
  512. */
  513. uchar*
  514. attachscreen(Rectangle *r, ulong *chan, int *d, int *width, int *softscreen)
  515. {
  516. *r = gscreen->r;
  517. *d = gscreen->depth;
  518. *chan = gscreen->chan;
  519. *width = gscreen->width;
  520. *softscreen = (landscape == 0);
  521. return (uchar *)gscreen->data->bdata;
  522. }
  523. void
  524. getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
  525. {
  526. USED(p, pr, pg, pb);
  527. }
  528. int
  529. setcolor(ulong p, ulong r, ulong g, ulong b)
  530. {
  531. USED(p, r, g, b);
  532. return 0;
  533. }
  534. void
  535. blankscreen(int blank)
  536. {
  537. if (blank)
  538. lcdon(0);
  539. else {
  540. lcdinit();
  541. lcdon(1);
  542. }
  543. }
  544. static void
  545. omapscreenputs(char *s, int n)
  546. {
  547. int i;
  548. Rune r;
  549. char buf[4];
  550. if (!islo()) {
  551. /* don't deadlock trying to print in interrupt */
  552. if (!canlock(&screenlock))
  553. return; /* discard s */
  554. } else
  555. lock(&screenlock);
  556. while (n > 0) {
  557. i = chartorune(&r, s);
  558. if (i == 0) {
  559. s++;
  560. --n;
  561. continue;
  562. }
  563. memmove(buf, s, i);
  564. buf[i] = 0;
  565. n -= i;
  566. s += i;
  567. screenputc(buf);
  568. }
  569. unlock(&screenlock);
  570. }
  571. static void
  572. screenwin(void)
  573. {
  574. char *greet;
  575. Memimage *orange;
  576. Point p, q;
  577. Rectangle r;
  578. memsetchan(gscreen, RGB16);
  579. back = memwhite;
  580. conscol = memblack;
  581. orange = allocmemimage(Rect(0, 0, 1, 1), RGB16);
  582. orange->flags |= Frepl;
  583. orange->clipr = gscreen->r;
  584. orange->data->bdata[0] = 0x40; /* magic: colour? */
  585. orange->data->bdata[1] = 0xfd; /* magic: colour? */
  586. w = memdefont->info[' '].width;
  587. h = memdefont->height;
  588. r = insetrect(gscreen->r, 4);
  589. memimagedraw(gscreen, r, memblack, ZP, memopaque, ZP, S);
  590. window = insetrect(r, 4);
  591. memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);
  592. memimagedraw(gscreen, Rect(window.min.x, window.min.y,
  593. window.max.x, window.min.y + h + 5 + 6), orange, ZP, nil, ZP, S);
  594. freememimage(orange);
  595. window = insetrect(window, 5);
  596. greet = " Plan 9 Console ";
  597. p = addpt(window.min, Pt(10, 0));
  598. q = memsubfontwidth(memdefont, greet);
  599. memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
  600. flushmemscreen(r);
  601. window.min.y += h + 6;
  602. curpos = window.min;
  603. window.max.y = window.min.y + ((window.max.y - window.min.y) / h) * h;
  604. }
  605. static void
  606. scroll(void)
  607. {
  608. int o;
  609. Point p;
  610. Rectangle r;
  611. /* move window contents up Scroll text lines */
  612. o = Scroll * h;
  613. r = Rpt(window.min, Pt(window.max.x, window.max.y - o));
  614. p = Pt(window.min.x, window.min.y + o);
  615. memimagedraw(gscreen, r, gscreen, p, nil, p, S);
  616. flushmemscreen(r);
  617. /* clear the bottom Scroll text lines */
  618. r = Rpt(Pt(window.min.x, window.max.y - o), window.max);
  619. memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
  620. flushmemscreen(r);
  621. curpos.y -= o;
  622. }
  623. static void
  624. screenputc(char *buf)
  625. {
  626. int w;
  627. uint pos;
  628. Point p;
  629. Rectangle r;
  630. static int *xp;
  631. static int xbuf[256];
  632. if (xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
  633. xp = xbuf;
  634. switch (buf[0]) {
  635. case '\n':
  636. if (curpos.y + h >= window.max.y)
  637. scroll();
  638. curpos.y += h;
  639. screenputc("\r");
  640. break;
  641. case '\r':
  642. xp = xbuf;
  643. curpos.x = window.min.x;
  644. break;
  645. case '\t':
  646. p = memsubfontwidth(memdefont, " ");
  647. w = p.x;
  648. if (curpos.x >= window.max.x - Tabstop * w)
  649. screenputc("\n");
  650. pos = (curpos.x - window.min.x) / w;
  651. pos = Tabstop - pos % Tabstop;
  652. *xp++ = curpos.x;
  653. r = Rect(curpos.x, curpos.y, curpos.x + pos * w, curpos.y + h);
  654. memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
  655. flushmemscreen(r);
  656. curpos.x += pos * w;
  657. break;
  658. case '\b':
  659. if (xp <= xbuf)
  660. break;
  661. xp--;
  662. r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
  663. memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
  664. flushmemscreen(r);
  665. curpos.x = *xp;
  666. break;
  667. case '\0':
  668. break;
  669. default:
  670. p = memsubfontwidth(memdefont, buf);
  671. w = p.x;
  672. if (curpos.x >= window.max.x - w)
  673. screenputc("\n");
  674. *xp++ = curpos.x;
  675. r = Rect(curpos.x, curpos.y, curpos.x + w, curpos.y + h);
  676. memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
  677. memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
  678. flushmemscreen(r);
  679. curpos.x += w;
  680. }
  681. }