video.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Florian Klaempfl
  5. member of the Free Pascal development team
  6. Video unit for OS/2
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit Video;
  14. interface
  15. {$i videoh.inc}
  16. implementation
  17. uses
  18. DosCalls, VioCalls;
  19. {$i video.inc}
  20. const
  21. InitVideoCalled: boolean = false;
  22. LastCursorType: word = crUnderline;
  23. EmptyCell: cardinal = $0720;
  24. OrigScreen: PVideoBuf = nil;
  25. OrigScreenSize: cardinal = 0;
  26. var OrigCurType: TVioCursorInfo;
  27. OrigVioMode: TVioModeInfo;
  28. OrigHighBit: TVioIntensity;
  29. OrigCurRow: word;
  30. OrigCurCol: word;
  31. CellHeight: byte;
  32. OldVideoBuf: PVideoBuf;
  33. procedure TargetEntry;
  34. var P: PVideoModeList;
  35. PScr: pointer;
  36. begin
  37. {Remember original video mode, cursor type and high bit behaviour setting}
  38. OrigVioMode.cb := SizeOf (OrigVioMode);
  39. VioGetMode (OrigVioMode, 0);
  40. VioGetCurType (OrigCurType, 0);
  41. VioGetCurPos (OrigCurRow, OrigCurCol, 0);
  42. with OrigHighBit do
  43. begin
  44. cb := 6;
  45. rType := 2;
  46. end;
  47. VioGetState (OrigHighBit, 0);
  48. {Register the curent video mode in Modes if not there yet}
  49. with OrigVioMode do
  50. begin
  51. P := Modes;
  52. while (P <> nil) and ((P^.Row <> Row) or (P^.Col <> Col)
  53. or (P^.Color <> (Color >= Colors_16))) do
  54. P := P^.Next;
  55. if P = nil then
  56. {Assume we have at least 16 colours available in "colour" modes}
  57. RegisterVideoMode (Col, Row, Color >= Colors_16,
  58. @DefaultVideoModeSelector, 0);
  59. end;
  60. {Get the address of the original videobuffer and size.}
  61. if VioGetBuf (PScr, PWord (@OrigScreenSize)^, 0) = 0 then
  62. begin
  63. PScr := SelToFlat (TFarPtr (PScr));
  64. GetMem (OrigScreen, OrigScreenSize);
  65. Move (PScr^, OrigScreen^, OrigScreenSize);
  66. end;
  67. end;
  68. procedure CheckCellHeight;
  69. var OldCD, CD: TVioCursorInfo;
  70. begin
  71. VioGetCurType (OldCD, 0);
  72. Move (OldCD, CD, SizeOf (CD));
  73. with CD do
  74. begin
  75. Attr := 0;
  76. yStart := word (-90);
  77. cEnd := word (-100);
  78. end;
  79. VioSetCurType (CD, 0);
  80. VioGetCurType (CD, 0);
  81. CellHeight := CD.cEnd;
  82. VioSetCurType (OldCD, 0);
  83. end;
  84. procedure RegisterVideoModes;
  85. begin
  86. { BW modes are rejected on my (colour) configuration. I can't imagine
  87. OS/2 running on MCGA anyway... ;-)
  88. RegisterVideoMode (40, 25, False, @DefaultVideoModeSelector, 0);
  89. RegisterVideoMode (80, 25, False, @DefaultVideoModeSelector, 0);
  90. }
  91. RegisterVideoMode (40, 25, True, @DefaultVideoModeSelector, 0);
  92. RegisterVideoMode (80, 25, True, @DefaultVideoModeSelector, 0);
  93. RegisterVideoMode (80, 30, True, @DefaultVideoModeSelector, 0);
  94. RegisterVideoMode (80, 43, True, @DefaultVideoModeSelector, 0);
  95. RegisterVideoMode (80, 50, True, @DefaultVideoModeSelector, 0);
  96. { The following modes wouldn't work on plain VGA; is it useful to check
  97. for their availability on the program startup?
  98. RegisterVideoMode (132, 25, True, @DefaultVideoModeSelector, 0);
  99. RegisterVideoMode (132, 30, True, @DefaultVideoModeSelector, 0);
  100. RegisterVideoMode (132, 43, True, @DefaultVideoModeSelector, 0);
  101. RegisterVideoMode (132, 50, True, @DefaultVideoModeSelector, 0);
  102. }
  103. end;
  104. procedure SetHighBitBlink (Blink: boolean);
  105. var VI: TVioIntensity;
  106. begin
  107. with VI do
  108. begin
  109. cb := 6;
  110. rType := 2;
  111. fs := byte (not (Blink));
  112. end;
  113. VioSetState (VI, 0);
  114. end;
  115. procedure InitVideo;
  116. var MI: TVioModeInfo;
  117. begin
  118. if InitVideoCalled then
  119. FreeMem (OldVideoBuf, VideoBufSize);
  120. OldVideoBuf := nil;
  121. InitVideoCalled := true;
  122. VideoBufSize := 0;
  123. MI.cb := SizeOf (MI);
  124. VioGetMode (MI, 0);
  125. with MI do
  126. begin
  127. ScreenWidth := Col;
  128. ScreenHeight := Row;
  129. ScreenColor := Color >= Colors_16;
  130. end;
  131. VioGetCurPos (CursorY, CursorX, 0);
  132. LowAscii := true;
  133. SetCursorType (LastCursorType);
  134. {Get the address of the videobuffer.}
  135. if VioGetBuf (VideoBuf, PWord (@VideoBufSize)^, 0) = 0 then
  136. begin
  137. VideoBuf := SelToFlat (TFarPtr (VideoBuf));
  138. SetHighBitBlink (true);
  139. GetMem (OldVideoBuf, VideoBufSize);
  140. Move (VideoBuf^, OldVideoBuf^, VideoBufSize);
  141. end
  142. else
  143. ErrorHandler (errVioInit, nil);
  144. end;
  145. procedure SetCursorPos (NewCursorX, NewCursorY: word);
  146. begin
  147. if VioSetCurPos (NewCursorY, NewCursorX, 0) = 0 then
  148. begin
  149. CursorX := NewCursorX;
  150. CursorY := NewCursorY;
  151. end
  152. else
  153. {Do not set an error code; people should fix invalid NewCursorX
  154. or NewCursorY values when designing, there is no need for detecting
  155. these errors at runtime.}
  156. RunError (225);
  157. end;
  158. function GetCursorType: word;
  159. var CD: TVioCursorInfo;
  160. begin
  161. VioGetCurType (CD, 0); {Never fails, because handle is default handle.}
  162. with CD do
  163. begin
  164. CursorLines := Succ (cEnd) - yStart;
  165. if Attr = word (-1) then
  166. GetCursorType := crHidden
  167. else
  168. {Because the cursor's start and end lines are returned, we'll have
  169. to guess heuristically what cursor type we have.}
  170. if CursorLines = 0 then
  171. {Probably this does not occur, but you'll never know.}
  172. GetCursorType := crHidden
  173. else if CursorLines <= Succ (CellHeight div 4) then
  174. GetCursorType := crUnderline
  175. else if CursorLines <= Succ (CellHeight div 2) then
  176. GetCursorType := crHalfBlock
  177. else
  178. GetCursorType := crBlock;
  179. end;
  180. end;
  181. procedure SetCursorType (NewType: word);
  182. var CD: TVioCursorInfo;
  183. begin
  184. VioGetCurType (CD, 0);
  185. with CD do
  186. begin
  187. case NewType of
  188. crHidden: Attr := word (-1);
  189. crUnderline:
  190. begin
  191. Attr := 0;
  192. yStart := word (-90);
  193. cEnd := word (-100);
  194. end;
  195. crHalfBlock:
  196. begin
  197. Attr := 0;
  198. yStart := word (-50);
  199. cEnd := word (-100);
  200. end;
  201. crBlock:
  202. begin
  203. Attr := 0;
  204. yStart := 0;
  205. cEnd := word (-100);
  206. end;
  207. end;
  208. VioSetCurType (CD, 0);
  209. VioGetCurType (CD, 0);
  210. CursorLines := Succ (cEnd) - yStart;
  211. end;
  212. end;
  213. procedure DoneVideo;
  214. var PScr: pointer;
  215. ScrSize: cardinal;
  216. begin
  217. if InitVideoCalled then
  218. begin
  219. LastCursorType := GetCursorType;
  220. ClearScreen;
  221. {Restore original settings}
  222. VioSetMode (OrigVioMode, 0);
  223. CheckCellHeight;
  224. {Set CursorX and CursorY}
  225. SetCursorPos (0, 0);
  226. VioSetState (OrigHighBit, 0);
  227. VioSetCurType (OrigCurType, 0);
  228. VioSetCurPos (OrigCurRow, OrigCurCol, 0);
  229. FreeMem (OldVideoBuf, VideoBufSize);
  230. OldVideoBuf := nil;
  231. VideoBufSize := 0;
  232. InitVideoCalled := false;
  233. if (OrigScreenSize <> 0) and (OrigScreen <> nil) then
  234. begin
  235. ScrSize := 0;
  236. if (VioGetBuf (PScr, PWord (@ScrSize)^, 0) = 0)
  237. and (ScrSize = OrigScreenSize) then
  238. begin
  239. PScr := SelToFlat (TFarPtr (PScr));
  240. Move (OrigScreen^, PScr^, OrigScreenSize);
  241. VioShowBuf (0, ScrSize, 0);
  242. end;
  243. end;
  244. end;
  245. end;
  246. function GetCapabilities: word;
  247. begin
  248. GetCapabilities := $3F;
  249. end;
  250. function DefaultVideoModeSelector (const VideoMode: TVideoMode; Params: longint): boolean;
  251. var OldMI, MI: TVioModeInfo;
  252. begin
  253. OldMI.cb := SizeOf (OldMI);
  254. if VioGetMode (OldMI, 0) <> 0 then
  255. DefaultVideoModeSelector := false
  256. else
  257. begin
  258. with MI do
  259. begin
  260. cb := 8;
  261. fbType := 1;
  262. if VideoMode.Color then
  263. Color := Colors_16
  264. else
  265. Color := Colors_2;
  266. Col := VideoMode.Col;
  267. Row := VideoMode.Row;
  268. end;
  269. if VioSetMode (MI, 0) = 0 then
  270. if VioGetBuf (VideoBuf, PWord (@VideoBufSize)^, 0) = 0 then
  271. begin
  272. VideoBuf := SelToFlat (TFarPtr (VideoBuf));
  273. DefaultVideoModeSelector := true;
  274. SetHighBitBlink (true);
  275. CheckCellHeight;
  276. SetCursorType (LastCursorType);
  277. ClearScreen;
  278. end
  279. else
  280. begin
  281. DefaultVideoModeSelector := false;
  282. VioSetMode (OldMI, 0);
  283. VioGetBuf (VideoBuf, PWord (@VideoBufSize)^, 0);
  284. VideoBuf := SelToFlat (TFarPtr (VideoBuf));
  285. SetHighBitBlink (true);
  286. CheckCellHeight;
  287. SetCursorType (LastCursorType);
  288. ClearScreen;
  289. end
  290. else
  291. begin
  292. DefaultVideoModeSelector := false;
  293. VioGetBuf (VideoBuf, PWord (@VideoBufSize)^, 0);
  294. VideoBuf := SelToFlat (TFarPtr (VideoBuf));
  295. SetHighBitBlink (true);
  296. SetCursorType (LastCursorType);
  297. end;
  298. end;
  299. end;
  300. procedure ClearScreen;
  301. begin
  302. VioScrollDn (0, 0, word (-1), word (-1), word (-1), PWord (@EmptyCell)^, 0);
  303. Move (VideoBuf^, OldVideoBuf^, VideoBufSize);
  304. end;
  305. {$ASMMODE INTEL}
  306. procedure UpdateScreen (Force: boolean);
  307. var SOfs, CLen: cardinal;
  308. begin
  309. if LockUpdateScreen = 0 then
  310. begin
  311. if not (Force) then
  312. begin
  313. asm
  314. cld
  315. mov esi, VideoBuf
  316. mov edi, OldVideoBuf
  317. mov eax, VideoBufSize
  318. mov ecx, eax
  319. shr ecx
  320. shr ecx
  321. repe
  322. cmpsd
  323. je @no_update
  324. inc cx
  325. mov SOfs, ecx
  326. mov Force, 1
  327. std
  328. mov edi, eax
  329. mov esi, VideoBuf
  330. add eax, esi
  331. sub eax, 4
  332. mov esi, eax
  333. mov eax, OldVideoBuf
  334. add eax, edi
  335. sub eax, 4
  336. mov edi, eax
  337. repe
  338. cmpsd
  339. inc ecx
  340. shl ecx
  341. shl ecx
  342. mov CLen, ecx
  343. cld
  344. @no_update:
  345. end;
  346. SOfs := VideoBufSize - (SOfs shl 2);
  347. end else
  348. begin
  349. SOfs := 0;
  350. CLen := VideoBufSize;
  351. end;
  352. if Force then
  353. begin
  354. VioShowBuf (SOfs, CLen, 0);
  355. Move (VideoBuf^ [SOfs div SizeOf (TVideoCell)],
  356. OldVideoBuf^ [SOfs div SizeOf (TVideoCell)], CLen);
  357. end;
  358. end;
  359. end;
  360. initialization
  361. RegisterVideoModes;
  362. TargetEntry;
  363. finalization
  364. UnRegisterVideoModes;
  365. end.
  366. {
  367. $Log$
  368. Revision 1.1 2001-01-13 11:03:58 peter
  369. * API 2 RTL commit
  370. }