video.inc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. {
  2. System independent low-level video interface for linux
  3. $Id$
  4. }
  5. uses
  6. Linux, Strings, FileCtrl, TermInfo;
  7. var
  8. LastCursorType : byte;
  9. TtyFd: Longint;
  10. Console: Boolean;
  11. OldVideoBuf: PVideoBuf;
  12. CurColor: Byte;
  13. {$ASMMODE ATT}
  14. procedure SendEscapeSeqNdx(Ndx: Word);
  15. var
  16. P: PChar;
  17. begin
  18. P:=cur_term^.ttype.Strings[Ndx];
  19. if assigned(p) then
  20. fdWrite(TTYFd, P^, StrLen(P));
  21. end;
  22. procedure SendEscapeSeq(const S: String);
  23. begin
  24. fdWrite(TTYFd, S[1], Length(S));
  25. end;
  26. Function IntStr(l:longint):string;
  27. var
  28. s : string;
  29. begin
  30. Str(l,s);
  31. IntStr:=s;
  32. end;
  33. Function XY2Ansi(x,y,ox,oy:longint):String;
  34. {
  35. Returns a string with the escape sequences to go to X,Y on the screen
  36. }
  37. Begin
  38. if y=oy then
  39. begin
  40. if x=ox then
  41. begin
  42. XY2Ansi:='';
  43. exit;
  44. end;
  45. if x=1 then
  46. begin
  47. XY2Ansi:=#13;
  48. exit;
  49. end;
  50. if x>ox then
  51. begin
  52. XY2Ansi:=#27'['+IntStr(x-ox)+'C';
  53. exit;
  54. end
  55. else
  56. begin
  57. XY2Ansi:=#27'['+IntStr(ox-x)+'D';
  58. exit;
  59. end;
  60. end;
  61. if x=ox then
  62. begin
  63. if y>oy then
  64. begin
  65. XY2Ansi:=#27'['+IntStr(y-oy)+'B';
  66. exit;
  67. end
  68. else
  69. begin
  70. XY2Ansi:=#27'['+IntStr(oy-y)+'A';
  71. exit;
  72. end;
  73. end;
  74. if (x=1) and (oy+1=y) then
  75. XY2Ansi:=#13#10
  76. else
  77. XY2Ansi:=#27'['+IntStr(y)+';'+IntStr(x)+'H';
  78. End;
  79. const
  80. AnsiTbl : string[8]='04261537';
  81. Function Attr2Ansi(Attr,OAttr:longint):string;
  82. {
  83. Convert Attr to an Ansi String, the Optimal code is calculate
  84. with use of the old OAttr
  85. }
  86. var
  87. hstr : string[16];
  88. OFg,OBg,Fg,Bg : longint;
  89. procedure AddSep(ch:char);
  90. begin
  91. if length(hstr)>0 then
  92. hstr:=hstr+';';
  93. hstr:=hstr+ch;
  94. end;
  95. begin
  96. if Attr=OAttr then
  97. begin
  98. Attr2Ansi:='';
  99. exit;
  100. end;
  101. Hstr:='';
  102. Fg:=Attr and $f;
  103. Bg:=Attr shr 4;
  104. OFg:=Attr and $f;
  105. OBg:=Attr shr 4;
  106. if (OFg<>7) or (Fg=7) or ((OFg>7) and (Fg<8)) or ((OBg>7) and (Bg<8)) then
  107. begin
  108. hstr:='0';
  109. OFg:=7;
  110. OBg:=0;
  111. end;
  112. if (Fg>7) and (OFg<8) then
  113. begin
  114. AddSep('1');
  115. OFg:=OFg or 8;
  116. end;
  117. if (Bg and 8)<>(OBg and 8) then
  118. begin
  119. AddSep('5');
  120. OBg:=OBg or 8;
  121. end;
  122. if (Fg<>OFg) then
  123. begin
  124. AddSep('3');
  125. hstr:=hstr+AnsiTbl[(Fg and 7)+1];
  126. end;
  127. if (Bg<>OBg) then
  128. begin
  129. AddSep('4');
  130. hstr:=hstr+AnsiTbl[(Bg and 7)+1];
  131. end;
  132. if hstr='0' then
  133. hstr:='';
  134. Attr2Ansi:=#27'['+hstr+'m';
  135. end;
  136. procedure UpdateTTY(Force:boolean);
  137. type
  138. tchattr=packed record
  139. ch : char;
  140. attr : byte;
  141. end;
  142. var
  143. outbuf : array[0..1023+255] of char;
  144. chattr : tchattr;
  145. skipped : boolean;
  146. outptr,
  147. spaces,
  148. eol,
  149. LastX,LastY,
  150. x,y,
  151. SpaceAttr,
  152. LastAttr : longint;
  153. p,pold : pvideocell;
  154. procedure outdata(hstr:string);
  155. begin
  156. while (eol>0) do
  157. begin
  158. hstr:=#13#10+hstr;
  159. dec(eol);
  160. end;
  161. move(hstr[1],outbuf[outptr],length(hstr));
  162. inc(outptr,length(hstr));
  163. if outptr>1024 then
  164. begin
  165. fdWrite(TTYFd,outbuf,outptr);
  166. outptr:=0;
  167. end;
  168. end;
  169. procedure OutClr(c:byte);
  170. begin
  171. if c=LastAttr then
  172. exit;
  173. OutData(Attr2Ansi(c,LastAttr));
  174. LastAttr:=c;
  175. end;
  176. procedure OutSpaces;
  177. begin
  178. if (Spaces=0) then
  179. exit;
  180. OutClr(SpaceAttr);
  181. OutData(Space(Spaces));
  182. LastX:=x;
  183. LastY:=y;
  184. Spaces:=0;
  185. end;
  186. begin
  187. OutPtr:=0;
  188. Eol:=0;
  189. skipped:=true;
  190. p:=PVideoCell(VideoBuf);
  191. pold:=PVideoCell(OldVideoBuf);
  192. { init Attr and X,Y }
  193. OutData(#27'[m'#27'[H');
  194. LastAttr:=7;
  195. LastX:=1;
  196. LastY:=1;
  197. for y:=1 to ScreenHeight do
  198. begin
  199. SpaceAttr:=0;
  200. Spaces:=0;
  201. for x:=1 to ScreenWidth do
  202. begin
  203. if (not force) and (p^=pold^) then
  204. begin
  205. if (Spaces>0) then
  206. OutSpaces;
  207. skipped:=true;
  208. end
  209. else
  210. begin
  211. if skipped then
  212. begin
  213. OutData(XY2Ansi(x,y,LastX,LastY));
  214. LastX:=x;
  215. LastY:=y;
  216. skipped:=false;
  217. end;
  218. chattr:=tchattr(p^);
  219. if chattr.ch in [#0,#255] then
  220. chattr.ch:=' ';
  221. if chattr.ch=' ' then
  222. begin
  223. if Spaces=0 then
  224. SpaceAttr:=chattr.Attr;
  225. if (chattr.attr and $f0)=(spaceattr and $f0) then
  226. chattr.Attr:=SpaceAttr
  227. else
  228. begin
  229. OutSpaces;
  230. SpaceAttr:=chattr.Attr;
  231. end;
  232. inc(Spaces);
  233. end
  234. else
  235. begin
  236. if (Spaces>0) then
  237. OutSpaces;
  238. if LastAttr<>chattr.Attr then
  239. OutClr(chattr.Attr);
  240. OutData(chattr.ch);
  241. LastX:=x+1;
  242. LastY:=y;
  243. end;
  244. p^:=tvideocell(chattr);
  245. end;
  246. inc(p);
  247. inc(pold);
  248. end;
  249. if (Spaces>0) then
  250. OutSpaces;
  251. if force then
  252. inc(eol);
  253. end;
  254. eol:=0;
  255. OutData(XY2Ansi(CursorX,CursorY,LastX,LastY));
  256. fdWrite(TTYFd,outbuf,outptr);
  257. end;
  258. procedure InitVideo;
  259. const
  260. fontstr : string[3]=#27'(K';
  261. var
  262. ThisTTY: String[30];
  263. FName: String;
  264. WS: packed record
  265. ws_row, ws_col, ws_xpixel, ws_ypixel: Word;
  266. end;
  267. Err: Longint;
  268. begin
  269. LowAscii:=false;
  270. if VideoBufSize<>0 then
  271. DoneVideo;
  272. { check for tty }
  273. ThisTTY:=TTYName(stdin);
  274. if IsATTY(stdin) then
  275. begin
  276. { write code to set a correct font }
  277. fdWrite(stdout,fontstr[1],length(fontstr));
  278. { running on a tty, find out whether locally or remotely }
  279. if (Copy(ThisTTY, 1, 8) = '/dev/tty') and
  280. (ThisTTY[9] >= '0') and (ThisTTY[9] <= '9') then
  281. begin
  282. { running on the console }
  283. FName:='/dev/vcsa' + ThisTTY[9];
  284. TTYFd:=OpenFile(FName, filReadWrite); { open console }
  285. end
  286. else
  287. TTYFd:=-1;
  288. if TTYFd<>-1 then
  289. Console:=true
  290. else
  291. begin
  292. { running on a remote terminal, no error with /dev/vcsa }
  293. Console:=False;
  294. TTYFd:=stdout;
  295. end;
  296. ioctl(stdin, TIOCGWINSZ, @WS);
  297. ScreenWidth:=WS.ws_Col;
  298. ScreenHeight:=WS.ws_Row;
  299. if WS.ws_Col=0 then
  300. WS.ws_Col:=80;
  301. if WS.ws_Row=0 then
  302. WS.ws_Row:=25;
  303. CurColor:=$07;
  304. CursorX:=1;
  305. CursorY:=1;
  306. ScreenColor:=True;
  307. { allocate pmode memory buffer }
  308. VideoBufSize:=ScreenWidth*ScreenHeight*2;
  309. GetMem(VideoBuf,VideoBufSize);
  310. GetMem(OldVideoBuf,VideoBufSize);
  311. { Start with a clear screen }
  312. if not Console then
  313. begin
  314. setupterm(nil, stdout, err);
  315. SendEscapeSeqNdx(cursor_home);
  316. SendEscapeSeqNdx(cursor_normal);
  317. SendEscapeSeqNdx(cursor_visible);
  318. SendEscapeSeqNdx(enter_ca_mode);
  319. SetCursorType(crUnderLine);
  320. end;
  321. ClearScreen;
  322. end
  323. else
  324. ErrorCode:=errVioInit; { not a TTY }
  325. end;
  326. procedure DoneVideo;
  327. begin
  328. if VideoBufSize=0 then
  329. exit;
  330. ClearScreen;
  331. if Console then
  332. SetCursorPos(1,1)
  333. else
  334. begin
  335. SendEscapeSeqNdx(exit_ca_mode);
  336. SendEscapeSeqNdx(cursor_home);
  337. SendEscapeSeqNdx(cursor_normal);
  338. SendEscapeSeqNdx(cursor_visible);
  339. SetCursorType(crUnderLine);
  340. SendEscapeSeq(#27'[H');
  341. end;
  342. FreeMem(VideoBuf,VideoBufSize);
  343. FreeMem(OldVideoBuf,VideoBufSize);
  344. VideoBufSize:=0;
  345. end;
  346. procedure ClearScreen;
  347. begin
  348. FillWord(VideoBuf^,VideoBufSize shr 1,$0720);
  349. if Console then
  350. UpdateScreen(true)
  351. else
  352. begin
  353. SendEscapeSeq(#27'[0m');
  354. SendEscapeSeqNdx(clear_screen);
  355. end;
  356. end;
  357. procedure UpdateScreen(Force: Boolean);
  358. var
  359. DoUpdate : boolean;
  360. begin
  361. if LockUpdateScreen<>0 then
  362. exit;
  363. if not force then
  364. begin
  365. {$ifdef i386}
  366. asm
  367. movl VideoBuf,%esi
  368. movl OldVideoBuf,%edi
  369. movl VideoBufSize,%ecx
  370. shrl $2,%ecx
  371. repe
  372. cmpsl
  373. orl %ecx,%ecx
  374. setne DoUpdate
  375. end;
  376. {$endif i386}
  377. end
  378. else
  379. DoUpdate:=true;
  380. if not DoUpdate then
  381. exit;
  382. if Console then
  383. begin
  384. fdSeek(TTYFd, 4, skBeg);
  385. fdWrite(TTYFd, VideoBuf^,VideoBufSize);
  386. end
  387. else
  388. begin
  389. UpdateTTY(force);
  390. end;
  391. Move(VideoBuf^, OldVideoBuf^, VideoBufSize);
  392. end;
  393. function GetCapabilities: Word;
  394. begin
  395. { about cpColor... we should check the terminfo database... }
  396. GetCapabilities:=cpUnderLine + cpBlink + cpColor;
  397. end;
  398. procedure SetCursorPos(NewCursorX, NewCursorY: Word);
  399. var
  400. Pos : array [1..2] of Byte;
  401. begin
  402. if Console then
  403. begin
  404. fdSeek(TTYFd, 2, skBeg);
  405. Pos[1]:=NewCursorX;
  406. Pos[2]:=NewCursorY;
  407. fdWrite(TTYFd, Pos, 2);
  408. end
  409. else
  410. begin
  411. { newcursorx,y is 0 based ! }
  412. SendEscapeSeq(XY2Ansi(NewCursorX+1,NewCursorY+1,0,0));
  413. end;
  414. CursorX:=NewCursorX+1;
  415. CursorY:=NewCursorY+1;
  416. end;
  417. function GetCursorType: Word;
  418. begin
  419. GetCursorType:=LastCursorType;
  420. end;
  421. procedure SetCursorType(NewType: Word);
  422. begin
  423. LastCursorType:=NewType;
  424. case NewType of
  425. crBlock :
  426. SendEscapeSeq(#27'[?17;0;64c');
  427. crHidden :
  428. SendEscapeSeq(#27'[?1c');
  429. else
  430. SendEscapeSeq(#27'[?2c');
  431. end;
  432. end;
  433. function DefaultVideoModeSelector(const VideoMode: TVideoMode; Params: Longint): Boolean;
  434. begin
  435. DefaultVideoModeSelector:=false;
  436. end;
  437. procedure RegisterVideoModes;
  438. begin
  439. end;
  440. {
  441. $Log$
  442. Revision 1.1 2000-01-06 01:20:31 peter
  443. * moved out of packages/ back to topdir
  444. Revision 1.1 1999/11/24 23:36:38 peter
  445. * moved to packages dir
  446. Revision 1.5 1999/07/05 21:38:19 peter
  447. * works now also on not /dev/tty* units
  448. * if col,row is 0,0 then take 80x25 by default
  449. Revision 1.4 1999/02/22 12:46:16 peter
  450. + lowascii boolean if ascii < #32 is handled correctly
  451. Revision 1.3 1999/02/08 10:34:26 peter
  452. * cursortype futher implemented
  453. Revision 1.2 1998/12/12 19:13:03 peter
  454. * keyboard updates
  455. * make test target, make all only makes units
  456. Revision 1.1 1998/12/04 12:48:30 peter
  457. * moved some dirs
  458. Revision 1.6 1998/12/03 10:18:07 peter
  459. * tty fixed
  460. Revision 1.5 1998/12/01 15:08:17 peter
  461. * fixes for linux
  462. Revision 1.4 1998/11/01 20:29:12 peter
  463. + lockupdatescreen counter to not let updatescreen() update
  464. Revision 1.3 1998/10/29 12:49:50 peter
  465. * more fixes
  466. Revision 1.1 1998/10/26 11:31:47 peter
  467. + inital include files
  468. }