video.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  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. asm
  313. cld
  314. mov esi, VideoBuf
  315. mov edi, OldVideoBuf
  316. mov eax, VideoBufSize
  317. mov ecx, eax
  318. shr ecx, 1
  319. shr ecx, 1
  320. repe
  321. cmpsd
  322. je @no_update
  323. inc ecx
  324. mov edx, eax
  325. mov ebx, ecx
  326. shl ebx, 1
  327. shl ebx, 1
  328. sub edx, ebx
  329. mov SOfs, edx
  330. mov Force, 1
  331. std
  332. mov edi, eax
  333. mov esi, VideoBuf
  334. add eax, esi
  335. sub eax, 4
  336. mov esi, eax
  337. mov eax, OldVideoBuf
  338. add eax, edi
  339. sub eax, 4
  340. mov edi, eax
  341. repe
  342. cmpsd
  343. inc ecx
  344. shl ecx, 1
  345. shl ecx, 1
  346. mov CLen, ecx
  347. @no_update:
  348. end
  349. else
  350. begin
  351. SOfs := 0;
  352. CLen := VideoBufSize;
  353. end;
  354. if Force then
  355. begin
  356. VioShowBuf (SOfs, CLen, 0);
  357. Move (VideoBuf^ [SOfs div SizeOf (TVideoCell)],
  358. OldVideoBuf^ [SOfs div SizeOf (TVideoCell)], CLen);
  359. end;
  360. end;
  361. end;
  362. initialization
  363. RegisterVideoModes;
  364. TargetEntry;
  365. finalization
  366. UnRegisterVideoModes;
  367. end.
  368. {
  369. $Log$
  370. Revision 1.4 2001-02-04 01:55:05 hajny
  371. * one more correction (not crucial)
  372. Revision 1.3 2001/02/01 21:35:36 hajny
  373. * correction of a previously introduced bug
  374. Revision 1.2 2001/01/23 20:23:56 hajny
  375. * another little optimization of UpdateScreen
  376. Revision 1.1 2001/01/13 11:03:58 peter
  377. * API 2 RTL commit
  378. }