video.inc 13 KB

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