video.inc 9.1 KB

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