video.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  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. {$ifdef logging}
  13. f: file;
  14. const
  15. logstart: string = '';
  16. nl: char = #10;
  17. logend: string = #10#10;
  18. {$endif logging}
  19. {$ASMMODE ATT}
  20. const
  21. can_delete_term : boolean = false;
  22. procedure SendEscapeSeqNdx(Ndx: Word);
  23. var
  24. P: PChar;
  25. begin
  26. if not assigned(cur_term_Strings) then
  27. RunError(219);
  28. P:=cur_term_Strings^[Ndx];
  29. if assigned(p) then
  30. fdWrite(TTYFd, P^, StrLen(P));
  31. end;
  32. procedure SendEscapeSeq(const S: String);
  33. begin
  34. fdWrite(TTYFd, S[1], Length(S));
  35. end;
  36. Function IntStr(l:longint):string;
  37. var
  38. s : string;
  39. begin
  40. Str(l,s);
  41. IntStr:=s;
  42. end;
  43. Function XY2Ansi(x,y,ox,oy:longint):String;
  44. {
  45. Returns a string with the escape sequences to go to X,Y on the screen
  46. }
  47. Begin
  48. if y=oy then
  49. begin
  50. if x=ox then
  51. begin
  52. XY2Ansi:='';
  53. exit;
  54. end;
  55. if x=1 then
  56. begin
  57. XY2Ansi:=#13;
  58. exit;
  59. end;
  60. if x>ox then
  61. begin
  62. XY2Ansi:=#27'['+IntStr(x-ox)+'C';
  63. exit;
  64. end
  65. else
  66. begin
  67. XY2Ansi:=#27'['+IntStr(ox-x)+'D';
  68. exit;
  69. end;
  70. end;
  71. if x=ox then
  72. begin
  73. if y>oy then
  74. begin
  75. XY2Ansi:=#27'['+IntStr(y-oy)+'B';
  76. exit;
  77. end
  78. else
  79. begin
  80. XY2Ansi:=#27'['+IntStr(oy-y)+'A';
  81. exit;
  82. end;
  83. end;
  84. if (x=1) and (oy+1=y) then
  85. XY2Ansi:=#13#10
  86. else
  87. XY2Ansi:=#27'['+IntStr(y)+';'+IntStr(x)+'H';
  88. End;
  89. const
  90. AnsiTbl : string[8]='04261537';
  91. Function Attr2Ansi(Attr,OAttr:longint):string;
  92. {
  93. Convert Attr to an Ansi String, the Optimal code is calculate
  94. with use of the old OAttr
  95. }
  96. var
  97. hstr : string[16];
  98. OFg,OBg,Fg,Bg : longint;
  99. procedure AddSep(ch:char);
  100. begin
  101. if length(hstr)>0 then
  102. hstr:=hstr+';';
  103. hstr:=hstr+ch;
  104. end;
  105. begin
  106. if Attr=OAttr then
  107. begin
  108. Attr2Ansi:='';
  109. exit;
  110. end;
  111. Hstr:='';
  112. Fg:=Attr and $f;
  113. Bg:=Attr shr 4;
  114. OFg:=OAttr and $f;
  115. OBg:=OAttr shr 4;
  116. if (OFg<>7) or (Fg=7) or ((OFg>7) and (Fg<8)) or ((OBg>7) and (Bg<8)) then
  117. begin
  118. hstr:='0';
  119. OFg:=7;
  120. OBg:=0;
  121. end;
  122. if (Fg>7) and (OFg<8) then
  123. begin
  124. AddSep('1');
  125. OFg:=OFg or 8;
  126. end;
  127. if (Bg and 8)<>(OBg and 8) then
  128. begin
  129. AddSep('5');
  130. OBg:=OBg or 8;
  131. end;
  132. if (Fg<>OFg) then
  133. begin
  134. AddSep('3');
  135. hstr:=hstr+AnsiTbl[(Fg and 7)+1];
  136. end;
  137. if (Bg<>OBg) then
  138. begin
  139. AddSep('4');
  140. hstr:=hstr+AnsiTbl[(Bg and 7)+1];
  141. end;
  142. if hstr='0' then
  143. hstr:='';
  144. Attr2Ansi:=#27'['+hstr+'m';
  145. end;
  146. procedure UpdateTTY(Force:boolean);
  147. type
  148. tchattr=packed record
  149. ch : char;
  150. attr : byte;
  151. end;
  152. var
  153. outbuf : array[0..1023+255] of char;
  154. chattr : tchattr;
  155. skipped : boolean;
  156. outptr,
  157. spaces,
  158. eol,
  159. LastX,LastY,
  160. x,y,
  161. SpaceAttr,
  162. LastAttr : longint;
  163. p,pold : pvideocell;
  164. procedure outdata(hstr:string);
  165. begin
  166. while (eol>0) do
  167. begin
  168. hstr:=#13#10+hstr;
  169. dec(eol);
  170. end;
  171. move(hstr[1],outbuf[outptr],length(hstr));
  172. inc(outptr,length(hstr));
  173. if outptr>=1024 then
  174. begin
  175. {$ifdef logging}
  176. blockwrite(f,logstart[1],length(logstart));
  177. blockwrite(f,nl,1);
  178. blockwrite(f,outptr,sizeof(outptr));
  179. blockwrite(f,nl,1);
  180. blockwrite(f,outbuf,outptr);
  181. blockwrite(f,nl,1);
  182. {$endif logging}
  183. fdWrite(TTYFd,outbuf,outptr);
  184. outptr:=0;
  185. end;
  186. end;
  187. procedure OutClr(c:byte);
  188. begin
  189. if c=LastAttr then
  190. exit;
  191. OutData(Attr2Ansi(c,LastAttr));
  192. LastAttr:=c;
  193. end;
  194. procedure OutSpaces;
  195. begin
  196. if (Spaces=0) then
  197. exit;
  198. OutClr(SpaceAttr);
  199. OutData(Space(Spaces));
  200. LastX:=x;
  201. LastY:=y;
  202. Spaces:=0;
  203. end;
  204. begin
  205. OutPtr:=0;
  206. Eol:=0;
  207. skipped:=true;
  208. p:=PVideoCell(VideoBuf);
  209. pold:=PVideoCell(OldVideoBuf);
  210. { init Attr and X,Y }
  211. OutData(#27'[m'#27'[H');
  212. LastAttr:=7;
  213. LastX:=1;
  214. LastY:=1;
  215. for y:=1 to ScreenHeight do
  216. begin
  217. SpaceAttr:=0;
  218. Spaces:=0;
  219. for x:=1 to ScreenWidth do
  220. begin
  221. if (not force) and (p^=pold^) then
  222. begin
  223. if (Spaces>0) then
  224. OutSpaces;
  225. skipped:=true;
  226. end
  227. else
  228. begin
  229. if skipped then
  230. begin
  231. OutData(XY2Ansi(x,y,LastX,LastY));
  232. LastX:=x;
  233. LastY:=y;
  234. skipped:=false;
  235. end;
  236. chattr:=tchattr(p^);
  237. if chattr.ch in [#0,#255] then
  238. chattr.ch:=' ';
  239. if chattr.ch=' ' then
  240. begin
  241. if Spaces=0 then
  242. SpaceAttr:=chattr.Attr;
  243. if (chattr.attr and $f0)=(spaceattr and $f0) then
  244. chattr.Attr:=SpaceAttr
  245. else
  246. begin
  247. OutSpaces;
  248. SpaceAttr:=chattr.Attr;
  249. end;
  250. inc(Spaces);
  251. end
  252. else
  253. begin
  254. if (Spaces>0) then
  255. OutSpaces;
  256. if ord(chattr.ch)<32 then
  257. begin
  258. Chattr.Attr:= $ff xor Chattr.Attr;
  259. ChAttr.ch:= chr(ord(chattr.ch)+$30);
  260. end;
  261. if LastAttr<>chattr.Attr then
  262. OutClr(chattr.Attr);
  263. OutData(chattr.ch);
  264. LastX:=x+1;
  265. LastY:=y;
  266. end;
  267. p^:=tvideocell(chattr);
  268. end;
  269. inc(p);
  270. inc(pold);
  271. end;
  272. if (Spaces>0) then
  273. OutSpaces;
  274. if force then
  275. inc(eol);
  276. end;
  277. eol:=0;
  278. OutData(XY2Ansi(CursorX,CursorY,LastX,LastY));
  279. {$ifdef logging}
  280. blockwrite(f,logstart[1],length(logstart));
  281. blockwrite(f,nl,1);
  282. blockwrite(f,outptr,sizeof(outptr));
  283. blockwrite(f,nl,1);
  284. blockwrite(f,outbuf,outptr);
  285. blockwrite(f,nl,1);
  286. {$endif logging}
  287. fdWrite(TTYFd,outbuf,outptr);
  288. end;
  289. var
  290. InitialVideoTio, preInitVideoTio, postInitVideoTio: linux.termios;
  291. inputRaw, outputRaw: boolean;
  292. procedure saveRawSettings(const tio: linux.termios);
  293. Begin
  294. with tio do
  295. begin
  296. inputRaw :=
  297. ((c_iflag and (IGNBRK or BRKINT or PARMRK or ISTRIP or
  298. INLCR or IGNCR or ICRNL or IXON)) = 0) and
  299. ((c_lflag and (ECHO or ECHONL or ICANON or ISIG or IEXTEN)) = 0);
  300. outPutRaw :=
  301. ((c_oflag and OPOST) = 0) and
  302. ((c_cflag and (CSIZE or PARENB)) = 0) and
  303. ((c_cflag and CS8) <> 0);
  304. end;
  305. end;
  306. procedure restoreRawSettings(tio: linux.termios);
  307. begin
  308. with tio do
  309. begin
  310. if inputRaw then
  311. begin
  312. c_iflag := c_iflag and (not (IGNBRK or BRKINT or PARMRK or ISTRIP or
  313. INLCR or IGNCR or ICRNL or IXON));
  314. c_lflag := c_lflag and
  315. (not (ECHO or ECHONL or ICANON or ISIG or IEXTEN));
  316. end;
  317. if outPutRaw then
  318. begin
  319. c_oflag := c_oflag and not(OPOST);
  320. c_cflag := c_cflag and not(CSIZE or PARENB) or CS8;
  321. end;
  322. end;
  323. TCSetAttr(1,TCSANOW,tio);
  324. end;
  325. procedure TargetEntry;
  326. begin
  327. TCGetAttr(1,InitialVideoTio);
  328. end;
  329. procedure TargetExit;
  330. begin
  331. TCSetAttr(1,TCSANOW,InitialVideoTio);
  332. end;
  333. procedure prepareInitVideo;
  334. begin
  335. TCGetAttr(1,preInitVideoTio);
  336. saveRawSettings(preInitVideoTio);
  337. end;
  338. procedure videoInitDone;
  339. begin
  340. TCGetAttr(1,postInitVideoTio);
  341. restoreRawSettings(postInitVideoTio);
  342. end;
  343. procedure prepareDoneVideo;
  344. var
  345. tio: linux.termios;
  346. begin
  347. TCGetAttr(1,tio);
  348. saveRawSettings(tio);
  349. TCSetAttr(1,TCSANOW,postInitVideoTio);
  350. end;
  351. procedure doneVideoDone;
  352. begin
  353. restoreRawSettings(preInitVideoTio);
  354. end;
  355. procedure InitVideo;
  356. const
  357. fontstr : string[3]=#27'(K';
  358. var
  359. ThisTTY: String[30];
  360. FName: String;
  361. WS: packed record
  362. ws_row, ws_col, ws_xpixel, ws_ypixel: Word;
  363. end;
  364. Err: Longint;
  365. prev_term : TerminalCommon_ptr1;
  366. begin
  367. {$ifndef CPUI386}
  368. LowAscii:=false;
  369. {$endif CPUI386}
  370. if VideoBufSize<>0 then
  371. begin
  372. clearscreen;
  373. if Console then
  374. SetCursorPos(1,1)
  375. else
  376. begin
  377. SendEscapeSeqNdx(cursor_home);
  378. SendEscapeSeq(#27'[H');
  379. end;
  380. exit;
  381. end;
  382. { check for tty }
  383. ThisTTY:=TTYName(stdin);
  384. if IsATTY(stdin) then
  385. begin
  386. { save current terminal characteristics and remove rawness }
  387. prepareInitVideo;
  388. { write code to set a correct font }
  389. fdWrite(stdout,fontstr[1],length(fontstr));
  390. { running on a tty, find out whether locally or remotely }
  391. if (Copy(ThisTTY, 1, 8) = '/dev/tty') and
  392. (ThisTTY[9] >= '0') and (ThisTTY[9] <= '9') then
  393. begin
  394. { running on the console }
  395. FName:='/dev/vcsa' + ThisTTY[9];
  396. TTYFd:=OpenFile(FName, filReadWrite); { open console }
  397. end
  398. else
  399. TTYFd:=-1;
  400. if TTYFd<>-1 then
  401. Console:=true
  402. else
  403. begin
  404. { running on a remote terminal, no error with /dev/vcsa }
  405. Console:=False;
  406. LowAscii:=false;
  407. TTYFd:=stdout;
  408. end;
  409. ioctl(stdin, TIOCGWINSZ, @WS);
  410. if WS.ws_Col=0 then
  411. WS.ws_Col:=80;
  412. if WS.ws_Row=0 then
  413. WS.ws_Row:=25;
  414. ScreenWidth:=WS.ws_Col;
  415. { TDrawBuffer only has FVMaxWidth elements
  416. larger values lead to crashes }
  417. if ScreenWidth> FVMaxWidth then
  418. ScreenWidth:=FVMaxWidth;
  419. ScreenHeight:=WS.ws_Row;
  420. CursorX:=1;
  421. CursorY:=1;
  422. ScreenColor:=True;
  423. { allocate pmode memory buffer }
  424. VideoBufSize:=ScreenWidth*ScreenHeight*2;
  425. GetMem(VideoBuf,VideoBufSize);
  426. GetMem(OldVideoBuf,VideoBufSize);
  427. { Start with a clear screen }
  428. if not Console then
  429. begin
  430. prev_term:=cur_term;
  431. setupterm(nil, stdout, err);
  432. can_delete_term:=assigned(prev_term) and (prev_term<>cur_term);
  433. SendEscapeSeqNdx(cursor_home);
  434. SendEscapeSeqNdx(cursor_normal);
  435. SendEscapeSeqNdx(cursor_visible);
  436. SendEscapeSeqNdx(enter_ca_mode);
  437. SetCursorType(crUnderLine);
  438. end
  439. else if not assigned(cur_term) then
  440. begin
  441. setupterm(nil, stdout, err);
  442. can_delete_term:=false;
  443. end;
  444. ClearScreen;
  445. {$ifdef logging}
  446. assign(f,'video.log');
  447. rewrite(f,1);
  448. {$endif logging}
  449. { save new terminal characteristics and possible restore rawness }
  450. videoInitDone;
  451. end
  452. else
  453. ErrorCode:=errVioInit; { not a TTY }
  454. end;
  455. procedure DoneVideo;
  456. begin
  457. if VideoBufSize=0 then
  458. exit;
  459. prepareDoneVideo;
  460. ClearScreen;
  461. if Console then
  462. SetCursorPos(1,1)
  463. else
  464. begin
  465. SendEscapeSeqNdx(exit_ca_mode);
  466. SendEscapeSeqNdx(cursor_home);
  467. SendEscapeSeqNdx(cursor_normal);
  468. SendEscapeSeqNdx(cursor_visible);
  469. SetCursorType(crUnderLine);
  470. SendEscapeSeq(#27'[H');
  471. end;
  472. FreeMem(VideoBuf,VideoBufSize);
  473. FreeMem(OldVideoBuf,VideoBufSize);
  474. VideoBufSize:=0;
  475. doneVideoDone;
  476. if can_delete_term then
  477. begin
  478. del_curterm(cur_term);
  479. can_delete_term:=false;
  480. end;
  481. {$ifdef logging}
  482. close(f);
  483. {$endif logging}
  484. end;
  485. procedure ClearScreen;
  486. begin
  487. FillWord(VideoBuf^,VideoBufSize shr 1,$0720);
  488. if Console then
  489. UpdateScreen(true)
  490. else
  491. begin
  492. SendEscapeSeq(#27'[0m');
  493. SendEscapeSeqNdx(clear_screen);
  494. end;
  495. end;
  496. procedure UpdateScreen(Force: Boolean);
  497. var
  498. DoUpdate : boolean;
  499. begin
  500. if LockUpdateScreen<>0 then
  501. exit;
  502. if not force then
  503. begin
  504. {$ifdef i386}
  505. asm
  506. movl VideoBuf,%esi
  507. movl OldVideoBuf,%edi
  508. movl VideoBufSize,%ecx
  509. shrl $2,%ecx
  510. repe
  511. cmpsl
  512. orl %ecx,%ecx
  513. setne DoUpdate
  514. end;
  515. {$endif i386}
  516. end
  517. else
  518. DoUpdate:=true;
  519. if not DoUpdate then
  520. exit;
  521. if Console then
  522. begin
  523. fdSeek(TTYFd, 4, skBeg);
  524. fdWrite(TTYFd, VideoBuf^,VideoBufSize);
  525. end
  526. else
  527. begin
  528. UpdateTTY(force);
  529. end;
  530. Move(VideoBuf^, OldVideoBuf^, VideoBufSize);
  531. end;
  532. function GetCapabilities: Word;
  533. begin
  534. { about cpColor... we should check the terminfo database... }
  535. GetCapabilities:=cpUnderLine + cpBlink + cpColor;
  536. end;
  537. procedure SetCursorPos(NewCursorX, NewCursorY: Word);
  538. var
  539. Pos : array [1..2] of Byte;
  540. begin
  541. if Console then
  542. begin
  543. fdSeek(TTYFd, 2, skBeg);
  544. Pos[1]:=NewCursorX;
  545. Pos[2]:=NewCursorY;
  546. fdWrite(TTYFd, Pos, 2);
  547. end
  548. else
  549. begin
  550. { newcursorx,y is 0 based ! }
  551. SendEscapeSeq(XY2Ansi(NewCursorX+1,NewCursorY+1,0,0));
  552. end;
  553. CursorX:=NewCursorX+1;
  554. CursorY:=NewCursorY+1;
  555. end;
  556. function GetCursorType: Word;
  557. begin
  558. GetCursorType:=LastCursorType;
  559. end;
  560. procedure SetCursorType(NewType: Word);
  561. begin
  562. LastCursorType:=NewType;
  563. case NewType of
  564. crBlock :
  565. SendEscapeSeq(#27'[?17;0;64c');
  566. crHidden :
  567. SendEscapeSeq(#27'[?1c');
  568. else
  569. SendEscapeSeq(#27'[?2c');
  570. end;
  571. end;
  572. function DefaultVideoModeSelector(const VideoMode: TVideoMode; Params: Longint): Boolean;
  573. begin
  574. DefaultVideoModeSelector:=false;
  575. end;
  576. procedure RegisterVideoModes;
  577. begin
  578. end;
  579. {
  580. $Log$
  581. Revision 1.6 2000-10-15 09:17:20 peter
  582. * merged more fixes
  583. Revision 1.5 2000/10/04 11:53:31 pierre
  584. Add TargetEntry and TargetExit (merged)
  585. Revision 1.4 2000/09/26 08:18:29 jonas
  586. + added preserving of rawness of terminal when going though
  587. init/donevideo
  588. * del_term() is now called in donevideo
  589. * if initvideo is called while the video is already initialized, the
  590. screen is cleared and the cursor is set home, instead of going
  591. through the whole donevideo and then initvideo
  592. (merged from fixes branch)
  593. Revision 1.3 2000/08/02 12:39:22 jonas
  594. * fixed crashes under ncurses 4 by adding auto-detection for ncurses 4/5
  595. * cur_term is not directly usable anymore for the largest part because
  596. of a different record layout in ncurses 4/5, therefore the pointers
  597. cur_term_booleans, cur_term_numbers, cur_term_strings and
  598. cur_term_common are now available
  599. * adapted video.inc to use the new naming convention
  600. (merged from fixes branch)
  601. Revision 1.2 2000/07/13 11:32:25 michael
  602. + removed logs
  603. }