video.pp 11 KB

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