video.pp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2006-2014 by Karoly Balogh
  4. member of the Free Pascal development team
  5. Video unit for Amiga, MorphOS and AROS
  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. {.$define VIDEODEBUG}
  14. {.$define WITHBUFFERING}
  15. {
  16. History
  17. 2013-01-09 Add on demand support for full-screen video
  18. }
  19. interface
  20. uses
  21. amigados, intuition, utility, sysutils;
  22. {$i videoh.inc}
  23. { Amiga specific calls, to help interaction between Keyboard, Mouse and
  24. Video units, and Free Vision }
  25. procedure GotCloseWindow;
  26. function HasCloseWindow: boolean;
  27. procedure GotResizeWindow;
  28. function HasResizeWindow(var winw:longint; var winh: longint): boolean;
  29. procedure GotRefreshWindow;
  30. procedure ToggleCursor(forceOff: boolean);
  31. procedure GotActiveWindow;
  32. function HasActiveWindow: boolean;
  33. procedure GotInactiveWindow;
  34. function HasInactiveWindow: boolean;
  35. procedure SetWindowTitle(const winTitle: AnsiString; const screenTitle: AnsiString);
  36. procedure TranslateToCharXY(const X,Y: LongInt; var CX,CY: LongInt);
  37. var
  38. VideoWindow: PWindow;
  39. implementation
  40. uses
  41. exec, agraphics;
  42. {$i video.inc}
  43. {$i videodata.inc}
  44. const
  45. VIDEOSCREENNAME = 'FPC Video Screen Output';
  46. var
  47. OS_Screen : PScreen = nil; // Holds optional screen pointer
  48. FPC_VIDEO_FULLSCREEN : Boolean = False; // Global that defines when we need to attempt opening on own screen
  49. var
  50. VideoColorMap : PColorMap;
  51. VideoPens : array[0..15] of LongInt;
  52. VideoFont : PByte;
  53. VideoFontHeight : DWord;
  54. OldSH, OldSW : longint;
  55. OldCursorX,
  56. OldCursorY : LongInt;
  57. CursorType : Word;
  58. OldCursorType : Word;
  59. CursorUpdateCnt : Word;
  60. CursorUpdateSpeed : Word;
  61. CursorState : boolean;
  62. ForceCursorUpdate : boolean;
  63. {$ifdef WITHBUFFERING}
  64. BitmapWidth, BitmapHeight: Integer;
  65. BufRp: PRastPort;
  66. {$endif}
  67. GotCloseWindowMsg : Boolean;
  68. GotResizeWindowMsg : Boolean;
  69. GotActiveWindowMsg : Boolean;
  70. GotInactiveWindowMsg : Boolean;
  71. LastL, LastT: Integer;
  72. LastW, LastH: Integer;
  73. WindowForReqSave: PWindow;
  74. Process: PProcess;
  75. FontBitmap: PBitmap;
  76. (*
  77. GetScreen: pScreen;
  78. Tries to open a custom screen, which attempt to clone the workbench,
  79. and returns the pointer to the screen. Result can be nil when failed
  80. otherwise the screen got opened correctly.
  81. *)
  82. function _OpenScreenTags(a: Pointer; tags: array of PtrUInt): pScreen;
  83. begin
  84. _OpenScreenTags:=OpenScreenTagList(a, @tags);
  85. end;
  86. Function GetScreen: pScreen;
  87. begin
  88. GetScreen:=_OpenScreenTags(nil,[
  89. SA_Title , PtrUInt(PChar(VIDEOSCREENNAME)),
  90. SA_Left , 0,
  91. SA_Top , 0,
  92. SA_ShowTitle , 0, // Do not show the screen's TitleBar
  93. SA_Type , PUBLICSCREEN_F, // pubscreen
  94. SA_PubName , PtrUInt(PChar(VIDEOSCREENNAME)),
  95. SA_Quiet , 1,
  96. SA_LikeWorkbench , 1, // Let OS
  97. TAG_END, TAG_END
  98. ]);
  99. {$ifdef VIDEODEBUG}
  100. if (GetScreen <> nil) then
  101. Writeln('DEBUG: Opened a new screen')
  102. else
  103. Writeln('ERROR: Failed to open new screen');
  104. {$endif}
  105. end;
  106. (*
  107. GetWindow: pWindow;
  108. Tries to create and open a window. Returns the pointer to
  109. the window or nil in case of failure.
  110. The routine keeps the global FPC_FULL_SCREEM option into
  111. account and act accordingly.
  112. In windowed mode it returns a window with another kind of
  113. settings then when it has to reside on it's own customscreen.
  114. *)
  115. function _OpenWindowTags(a: Pointer; tags: array of PtrUInt): pWindow;
  116. begin
  117. _OpenWindowTags:=OpenWindowTagList(a, @tags);
  118. end;
  119. const
  120. VIDEO_IDCMP_DEFAULTS = IDCMP_RAWKEY or
  121. IDCMP_MOUSEBUTTONS or
  122. IDCMP_CHANGEWINDOW or IDCMP_CLOSEWINDOW or
  123. IDCMP_ACTIVEWINDOW or IDCMP_INACTIVEWINDOW or
  124. IDCMP_REFRESHWINDOW or
  125. IDCMP_INTUITICKS;
  126. { simple refresh would be nicer here, but smart refresh gives better
  127. results when moving around the window with the input blocked.
  128. (eg. compiling in the IDE) }
  129. VIDEO_WFLG_DEFAULTS = WFLG_RMBTRAP or WFLG_SMART_REFRESH;
  130. Function GetWindow: PWindow;
  131. var
  132. envBuf: array[0..15] of char;
  133. videoDefaultFlags: PtrUInt;
  134. begin
  135. videoDefaultFlags:=VIDEO_WFLG_DEFAULTS;
  136. if GetVar('FPC_VIDEO_SIMPLEREFRESH',@envBuf,sizeof(envBuf),0) > -1 then
  137. videoDefaultFlags:=videoDefaultFlags and not WFLG_SMART_REFRESH;
  138. if FPC_VIDEO_FULLSCREEN then
  139. begin
  140. OS_Screen := GetScreen;
  141. If OS_Screen = nil then
  142. Exit;
  143. {$ifdef VIDEODEBUG}
  144. WriteLn('DEBUG: Opened customscreen succesfully');
  145. {$endif}
  146. GetWindow:=_OpenWindowTags(nil, [
  147. WA_CustomScreen, PtrUint(OS_Screen),
  148. WA_Left , 0,
  149. WA_Top , 0,
  150. WA_InnerWidth , (OS_Screen^.Width div 8) * 8,
  151. WA_InnerHeight, (OS_Screen^.Height div 16) * 16,
  152. WA_AutoAdjust , 1,
  153. WA_Activate , 1,
  154. WA_Borderless , 1,
  155. WA_BackDrop , 1,
  156. WA_FLAGS , VIDEO_WFLG_DEFAULTS,
  157. WA_IDCMP , VIDEO_IDCMP_DEFAULTS,
  158. TAG_END, TAG_END
  159. ]);
  160. end else
  161. begin // Windowed Mode
  162. GetWindow:=_OpenWindowTags(nil, [
  163. WA_Left , LastL,
  164. WA_Top , LastT,
  165. WA_InnerWidth , LastW*8,
  166. WA_InnerHeight, LastH*VideoFontHeight,
  167. WA_MaxWidth , 32768,
  168. WA_MaxHeight , 32768,
  169. WA_Title , PtrUInt(PChar('FPC Video Window Output')),
  170. WA_Activate , 1,
  171. WA_FLAGS , (VIDEO_WFLG_DEFAULTS or
  172. WFLG_DRAGBAR or WFLG_DEPTHGADGET or WFLG_SIZEGADGET or
  173. WFLG_SIZEBBOTTOM or WFLG_CLOSEGADGET),
  174. WA_IDCMP , VIDEO_IDCMP_DEFAULTS,
  175. TAG_END, TAG_END
  176. ]);
  177. end;
  178. Process := PProcess(FindTask(nil));
  179. WindowForReqSave := Process^.pr_WindowPtr;
  180. Process^.pr_WindowPtr := GetWindow;
  181. {$ifdef VIDEODEBUG}
  182. If GetWindow <> nil then
  183. WriteLn('DEBUG: Sucessfully opened videounit Window')
  184. else
  185. WriteLn('ERROR: Failed to open videounit Window');
  186. {$endif}
  187. end;
  188. // ==========================================================================
  189. // ==
  190. // == Original source code continues, with minor adjustments
  191. // ==
  192. // ==========================================================================
  193. procedure SysInitVideo;
  194. var
  195. Counter,
  196. Counter2: LongInt;
  197. P: PWord;
  198. flags: DWord;
  199. envBuf: array[0..15] of char;
  200. begin
  201. {$IFDEF MORPHOS}
  202. InitGraphicsLibrary;
  203. InitIntuitionLibrary;
  204. {$ENDIF}
  205. {$ifdef VIDEODEBUG}
  206. WriteLn('FULLSCREEN VIDEO UNIT MODIFICATION v2');
  207. if FPC_VIDEO_FULLSCREEN then
  208. WriteLn('DEBUG: Recognized fullscreen mode')
  209. else
  210. WriteLn('DEBUG: Recognized windowed mode');
  211. {$endif}
  212. { FIXME/TODO: next to the hardwired selection, there could be some heuristics,
  213. which sets the font size correctly on screens according to the aspect
  214. ratio. (KB) }
  215. VideoFont:=@vgafont;
  216. VideoFontHeight:=16;
  217. if GetVar('FPC_VIDEO_BUILTINFONT',@envBuf,sizeof(envBuf),0) > -1 then
  218. begin
  219. case lowerCase(envBuf) of
  220. 'vga8':
  221. begin
  222. VideoFont:=@vgafont8;
  223. VideoFontHeight:=8;
  224. end;
  225. 'vga14':
  226. begin
  227. VideoFont:=@vgafont14;
  228. VideoFontHeight:=14;
  229. end;
  230. end;
  231. end;
  232. // fill videobuf and oldvideobuf with different bytes, to allow proper first draw
  233. FillDword(VideoBuf^, VideoBufSize div 4, $1234D3AD);
  234. FillDword(OldVideoBuf^, VideoBufSize div 4, $4321BEEF);
  235. VideoWindow := GetWindow;
  236. // nice hardcode values are probably going to mess things up
  237. // so we need a way to determine how many characters would fit
  238. // the screen in both directions. Try to be as accurate as possible.
  239. if FPC_VIDEO_FULLSCREEN then
  240. begin
  241. // just to make sure that we are going to use the window width
  242. // and height instead of the screen dimensions.
  243. // This is to circumvent that the window (or virtual window from
  244. // vision based on characters pixels * characters in both
  245. // dimensions) is actually smaller then the window it resides on.
  246. //
  247. // Can happen for instance when the window does not hide its
  248. // borders or titlebar as intended.
  249. ScreenWidth := VideoWindow^.GZZWidth div 8;
  250. ScreenHeight := VideoWindow^.GZZHeight div VideoFontHeight;
  251. ScreenColor := False;
  252. {$ifdef VIDEODEBUG}
  253. Writeln('DEBUG: Fullscreen - windowed - Width * Heigth = ',ScreenWidth,' * ',ScreenHeight);
  254. {$endif}
  255. end else
  256. begin
  257. ScreenWidth := LastW;
  258. ScreenHeight := LastH;
  259. ScreenColor := True;
  260. end;
  261. {$ifdef WITHBUFFERING}
  262. BufRp^.Bitmap := AllocBitmap(VideoWindow^.InnerWidth, VideoWindow^.InnerHeight, VideoWindow^.RPort^.Bitmap^.Depth, BMF_CLEAR, VideoWindow^.RPort^.Bitmap);
  263. BitmapWidth := VideoWindow^.InnerWidth;
  264. BitmapHeight := VideoWindow^.InnerHeight;
  265. {$endif}
  266. { viewpostcolormap info }
  267. videoColorMap := pScreen(videoWindow^.WScreen)^.ViewPort.ColorMap;
  268. for Counter := 0 to 15 do
  269. begin
  270. VideoPens[Counter] := ObtainBestPenA(VideoColorMap,
  271. vgacolors[counter, 0] shl 24, vgacolors[counter, 1] shl 24, vgacolors[counter, 2] shl 24, nil);
  272. {$ifdef VIDEODEBUG}
  273. If VideoPens[Counter] = -1 then
  274. WriteLn('errr color[',Counter,'] = ', VideoPens[Counter])
  275. else
  276. WriteLn('good color[',Counter,'] = ', VideoPens[Counter]);
  277. {$endif}
  278. end;
  279. { Obtain Friend bitmap for font blitting }
  280. FontBitmap:=AllocBitMap(16,VideoFontHeight*256,1,0,VideoWindow^.RPort^.Bitmap);
  281. if (FontBitmap <> nil) then
  282. begin
  283. flags:=GetBitmapAttr(FontBitmap,BMA_FLAGS);
  284. if (Flags and BMF_STANDARD) > 0 then
  285. begin
  286. {$ifdef VIDEODEBUG}
  287. writeln('Using fontbitmap mode.');
  288. {$endif}
  289. { Locking the bitmap would be better, but that requires CGFX/P96/etc specific calls }
  290. Forbid();
  291. { We need to make the data word wide, otherwise the blit will fail
  292. miserably on classics (tested on 3.1 + AGA) }
  293. p:=PWord(FontBitmap^.Planes[0]);
  294. for counter:=0 to 255 do
  295. for counter2:=0 to VideoFontHeight-1 do
  296. begin
  297. p^:=VideoFont[counter * VideoFontHeight + counter2] shl 8;
  298. inc(p);
  299. end;
  300. Permit();
  301. end
  302. else
  303. begin
  304. {$ifdef VIDEODEBUG}
  305. writeln('Using direct-from-fontdata mode.');
  306. {$endif}
  307. FreeBitmap(FontBitmap);
  308. FontBitmap:=nil;
  309. end;
  310. end;
  311. CursorX := 0;
  312. CursorY := 0;
  313. OldCursorX := 0;
  314. OldCursorY := 0;
  315. CursorType := crHidden;
  316. OldCursorType := crHidden;
  317. CursorState := true;
  318. ForceCursorUpdate:=false;
  319. CursorUpdateSpeed:=2; // this could come from an env-var or something
  320. CursorUpdateCnt:=0;
  321. GotCloseWindowMsg := false;
  322. GotResizeWindowMsg := false;
  323. GotActiveWindowMsg := false;
  324. GotInactiveWindowMsg := false;
  325. end;
  326. procedure SysDoneVideo;
  327. var
  328. Counter: LongInt;
  329. msg: PMessage;
  330. begin
  331. if VideoWindow <> nil then
  332. begin
  333. Process^.pr_WindowPtr := WindowForReqSave;
  334. if not FPC_VIDEO_FULLSCREEN then
  335. begin
  336. LastL := VideoWindow^.LeftEdge;
  337. LastT := VideoWindow^.TopEdge;
  338. end;
  339. // clean up the messages from our window before closing
  340. Forbid();
  341. repeat
  342. msg:=GetMsg(videoWindow^.UserPort);
  343. if (msg <> nil) then ReplyMsg(msg);
  344. until msg = nil;
  345. ModifyIDCMP(videoWindow,0);
  346. Permit();
  347. CloseWindow(videoWindow);
  348. VideoWindow := nil;
  349. end;
  350. FreeBitMap(FontBitmap);
  351. {$ifdef WITHBUFFERING}
  352. FreeBitmap(BufRp^.Bitmap);
  353. BufRp^.Bitmap := nil;
  354. {$endif}
  355. for Counter := 0 to 15 do
  356. ReleasePen(VideoColorMap, VideoPens[Counter]);
  357. if ((FPC_VIDEO_FULLSCREEN) and (OS_Screen <> nil)) then
  358. begin
  359. CloseScreen(OS_Screen);
  360. end;
  361. end;
  362. function SysSetVideoMode(const Mode: TVideoMode): Boolean;
  363. var
  364. dx: integer;
  365. dy: integer;
  366. begin
  367. if ScreenColor <> Mode.Color then
  368. begin
  369. SysDoneVideo;
  370. FPC_VIDEO_FULLSCREEN := not Mode.color;
  371. if not FPC_VIDEO_FULLSCREEN then
  372. begin
  373. LastT := 50;
  374. LastL := 50;
  375. LastW := 80;
  376. LastH := 25;
  377. end;
  378. SysInitVideo;
  379. end else
  380. if not FPC_VIDEO_FULLSCREEN then
  381. begin
  382. dx := (Mode.col * 8) - VideoWindow^.GZZWidth;
  383. dy := (Mode.row * VideoFontHeight) - VideoWindow^.GZZHeight;
  384. SizeWindow(videoWindow, dx, dy);
  385. end;
  386. ScreenWidth := Mode.col;
  387. ScreenHeight := Mode.row;
  388. LastW := Mode.Col;
  389. LastH := Mode.Row;
  390. ScreenColor := Mode.color;
  391. SysSetVideoMode := True;
  392. end;
  393. procedure SysClearScreen;
  394. begin
  395. oldSH := -1;
  396. oldSW := -1;
  397. UpdateScreen(True);
  398. end;
  399. procedure DrawChar(rp: PRastPort; x, y: LongInt; crType: Word);
  400. var
  401. TmpCharData: Word;
  402. TmpChar: Byte;
  403. TmpFGColor: Byte;
  404. TmpBGColor: Byte;
  405. sX, sY: LongInt;
  406. begin
  407. TmpCharData := VideoBuf^[y * ScreenWidth + x];
  408. TmpChar := byte(TmpCharData);
  409. TmpFGColor := (TmpCharData shr 8) and %00001111;
  410. TmpBGColor := (TmpCharData shr 12) and %00000111;
  411. sX := x * 8 + videoWindow^.borderLeft;
  412. sY := y * VideoFontHeight + videoWindow^.borderTop;
  413. if crType <> crBlock then
  414. begin
  415. SetABPenDrMd(rp, VideoPens[TmpFGColor], VideoPens[tmpBGColor], JAM2);
  416. end else
  417. begin
  418. { in case of block cursor, swap fg/bg colors
  419. and BltTemplate() below will take care of everything }
  420. SetABPenDrMd(rp, VideoPens[tmpBGColor], VideoPens[tmpFGColor], JAM2);
  421. end;
  422. if FontBitmap <> nil then
  423. BltTemplate(@(PWord(FontBitmap^.Planes[0])[tmpChar * VideoFontHeight]), 0, 2, rp, sX, sY, 8, VideoFontHeight)
  424. else
  425. BltTemplate(@VideoFont[tmpChar * VideoFontHeight], 0, 1, rp, sX, sY, 8, VideoFontHeight);
  426. if crType = crUnderLine then
  427. begin
  428. { draw two lines at the bottom of the char, in case of underline cursor }
  429. if videoFontHeight = 8 then
  430. begin
  431. GfxMove(rp, sX, sY + 7); Draw(rp, sX + 7, sY + 7);
  432. end
  433. else
  434. begin
  435. GfxMove(rp, sX, sY + videoFontHeight - 2); Draw(rp, sX + 7, sY + videoFontHeight - 2);
  436. GfxMove(rp, sX, sY + videoFontHeight - 1); Draw(rp, sX + 7, sY + videoFontHeight - 1);
  437. end;
  438. end;
  439. end;
  440. procedure SysUpdateScreen(Force: Boolean);
  441. var
  442. BufCounter: Longint;
  443. SmallForce: Boolean;
  444. Counter, CounterX, CounterY: LongInt;
  445. //BufRp: PRastPort;
  446. t: Double;
  447. NumChanged: Integer;
  448. begin
  449. SmallForce := False;
  450. // override forced update when screen dimensions haven't changed
  451. if Force then
  452. begin
  453. if (OldSH = ScreenHeight) and (OldSW = ScreenWidth) then
  454. Force := false
  455. else
  456. begin
  457. OldSH := ScreenHeight;
  458. OldSW := ScreenWidth;
  459. end;
  460. end;
  461. if Force then
  462. begin
  463. SmallForce:=true;
  464. end else
  465. begin
  466. Counter:=0;
  467. if not ForceCursorUpdate then
  468. while not smallforce and (Counter < (VideoBufSize div 4) - 1) do
  469. begin
  470. SmallForce := (PDWord(VideoBuf)[Counter] <> PDWord(OldVideoBuf)[Counter]);
  471. inc(Counter);
  472. end;
  473. end;
  474. {$ifdef WITHBUFFERING}
  475. if (VideoWindow^.InnerWidth > BitmapWidth) or (VideoWindow^.InnerHeight > BitmapHeight) then
  476. begin
  477. FreeBitmap(BufRp^.Bitmap);
  478. BufRp^.Bitmap := AllocBitmap(VideoWindow^.InnerWidth, VideoWindow^.InnerHeight, VideoWindow^.RPort^.Bitmap^.Depth, BMF_CLEAR, VideoWindow^.RPort^.Bitmap);
  479. BitmapWidth := VideoWindow^.InnerWidth;
  480. BitmapHeight := VideoWindow^.InnerHeight;
  481. Force := True;
  482. Smallforce := True;
  483. end;
  484. {$endif}
  485. BufCounter:=0;
  486. NumChanged:=0;
  487. if Smallforce then
  488. begin
  489. //t := now();
  490. for CounterY := 0 to ScreenHeight - 1 do
  491. begin
  492. for CounterX := 0 to ScreenWidth - 1 do
  493. begin
  494. if (VideoBuf^[BufCounter] <> OldVideoBuf^[BufCounter]) or Force then
  495. begin
  496. {$ifdef WITHBUFFERING}
  497. DrawChar(BufRp, CounterX, CounterY, crHidden);
  498. {$else}
  499. DrawChar(VideoWindow^.RPort, CounterX, CounterY, crHidden);
  500. {$endif}
  501. OldVideoBuf^[BufCounter] := VideoBuf^[BufCounter];
  502. Inc(NumChanged);
  503. end;
  504. Inc(BufCounter);
  505. end;
  506. end;
  507. //if NumChanged > 100 then
  508. // writeln('redraw time: ', floattoStrF((Now-t)* 24 * 60 * 60 * 1000000 / NumChanged, fffixed, 8,3), ' us/char' ); // ms
  509. end;
  510. if (CursorType <> OldCursorType) or
  511. (CursorX <> OldCursorX) or (CursorY <> OldCursorY) or
  512. SmallForce or ForceCursorUpdate then
  513. begin
  514. {$ifdef WITHBUFFERING}
  515. DrawChar(BufRp, OldCursorX, OldCursorY, crHidden);
  516. if CursorState then DrawChar(BufRp, CursorX, CursorY, CursorType);
  517. {$else}
  518. DrawChar(VideoWindow^.RPort, OldCursorX, OldCursorY, crHidden);
  519. if CursorState then DrawChar(VideoWindow^.RPort, CursorX, CursorY, CursorType);
  520. {$endif}
  521. OldCursorX := CursorX;
  522. OldCursorY := CursorY;
  523. OldcursorType := CursorType;
  524. end;
  525. {$ifdef WITHBUFFERING}
  526. BltBitMapRastPort(BufRp^.Bitmap, 0, 0, VideoWindow^.RPort, 0, 0, ScreenWidth * 8, ScreenHeight * 16, $00C0);
  527. {$endif}
  528. end;
  529. procedure SysSetCursorPos(NewCursorX, NewCursorY: Word);
  530. begin
  531. CursorX := NewCursorX;
  532. CursorY := NewCursorY;
  533. SysUpdateScreen(False);
  534. end;
  535. function SysGetCapabilities: Word;
  536. begin
  537. SysGetCapabilities := cpColor or cpChangeCursor;
  538. end;
  539. function SysGetCursorType: Word;
  540. begin
  541. SysGetCursorType := cursorType;
  542. end;
  543. procedure SysSetCursorType(NewType: Word);
  544. begin
  545. cursorType := newType;
  546. { FIXME: halfBlock cursors are not supported for now
  547. by the rendering code }
  548. if CursorType = crHalfBlock then
  549. cursorType := crBlock;
  550. SysUpdateScreen(False);
  551. end;
  552. // Amiga specific calls
  553. procedure GotCloseWindow;
  554. begin
  555. GotCloseWindowMsg := True;
  556. end;
  557. function HasCloseWindow: Boolean;
  558. begin
  559. HasCloseWindow := GotCloseWindowMsg;
  560. GotCloseWindowMsg := False;
  561. end;
  562. procedure GotResizeWindow;
  563. begin
  564. GotResizeWindowMsg := True;
  565. end;
  566. function HasResizeWindow(var WinW: LongInt; var WinH: LongInt): Boolean;
  567. begin
  568. WinW := 0;
  569. WinH := 0;
  570. HasResizeWindow := GotResizeWindowMsg;
  571. if GotResizeWindowMsg then
  572. begin
  573. //writeln('Has resize ', GotResizeWindowMsg);
  574. if Assigned(VideoWindow) then
  575. begin
  576. WinW := VideoWindow^.GZZWidth div 8;
  577. WinH := VideoWindow^.GZZHeight div VideoFontHeight;
  578. // writeln('resize', winw, ' ',winh);
  579. LastW := WinW;
  580. LastH := WinH;
  581. end
  582. end
  583. else
  584. begin
  585. WinW := LastW;
  586. WinH := LastH;
  587. end;
  588. GotResizeWindowMsg := False;
  589. end;
  590. procedure GotRefreshWindow;
  591. begin
  592. if assigned(VideoWindow) then
  593. begin
  594. oldSH := -1;
  595. oldSW := -1;
  596. BeginRefresh(VideoWindow);
  597. SysUpdateScreen(true);
  598. EndRefresh(VideoWindow, true);
  599. end;
  600. end;
  601. procedure ToggleCursor(forceOff: boolean);
  602. begin
  603. if CursorType = crHidden then exit;
  604. if forceOff then
  605. begin
  606. CursorState:=false;
  607. // to immediately turn on cursor on the next toggle
  608. CursorUpdateCnt:=CursorUpdateSpeed;
  609. end
  610. else
  611. begin
  612. Inc(CursorUpdateCnt);
  613. if CursorUpdateCnt >= CursorUpdateSpeed then
  614. begin
  615. CursorState:=not CursorState;
  616. CursorUpdateCnt:=0;
  617. end
  618. else
  619. exit;
  620. end;
  621. ForceCursorUpdate:=true;
  622. SysUpdateScreen(False);
  623. ForceCursorUpdate:=false;
  624. end;
  625. procedure GotActiveWindow;
  626. begin
  627. GotActiveWindowMsg:=true;
  628. end;
  629. function HasActiveWindow: boolean;
  630. begin
  631. HasActiveWindow:=GotActiveWindowMsg;
  632. GotActiveWindowMsg:=false;
  633. end;
  634. procedure GotInactiveWindow;
  635. begin
  636. GotInactiveWindowMsg:=true;
  637. end;
  638. function HasInactiveWindow: boolean;
  639. begin
  640. HasInactiveWindow:=GotInactiveWindowMsg;
  641. GotInactiveWindowMsg:=false;
  642. end;
  643. { SetWindowTitles seems not to copy the buffer, at least on AROS.
  644. So we better keep a reference of the strings to ourselves... }
  645. var
  646. globWinT: AnsiString;
  647. globScreenT: AnsiString;
  648. procedure SetWindowTitle(const winTitle: AnsiString; const screenTitle: AnsiString);
  649. var
  650. winT: PChar;
  651. screenT: PChar;
  652. begin
  653. globWinT:=winTitle;
  654. globScreenT:=screenTitle;
  655. if VideoWindow <> nil then
  656. begin
  657. if globWinT = '' then
  658. winT:=PChar(PtrInt(-1))
  659. else
  660. winT:=PChar(globWinT);
  661. if globScreenT = '' then
  662. screenT:=PChar(PtrInt(-1))
  663. else
  664. screenT:=PChar(globScreenT);
  665. SetWindowTitles(VideoWindow, winT, screenT);
  666. end;
  667. end;
  668. procedure TranslateToCharXY(const X,Y: LongInt; var CX,CY: LongInt);
  669. begin
  670. CX:=X div 8;
  671. CY:=Y div VideoFontHeight;
  672. end;
  673. function SysGetVideoModeCount: Word;
  674. begin
  675. SysGetVideoModeCount := 2;
  676. end;
  677. function SysGetVideoModeData(Index: Word; var Mode: TVideoMode): Boolean;
  678. var
  679. Screen: PScreen;
  680. begin
  681. case Index of
  682. 0: begin
  683. Mode.Col := 80;
  684. Mode.Row := 25;
  685. Mode.Color := True;
  686. end;
  687. 1: begin
  688. Screen := LockPubScreen('Workbench');
  689. Mode.Col := Screen^.Width div 8;
  690. Mode.Row := Screen^.Height div VideoFontHeight;
  691. UnlockPubScreen('Workbench', Screen);
  692. Mode.Color := False;
  693. end;
  694. end;
  695. SysGetVideoModeData := True;
  696. end;
  697. const
  698. SysVideoDriver : TVideoDriver = (
  699. InitDriver : @SysInitVideo;
  700. DoneDriver : @SysDoneVideo;
  701. UpdateScreen : @SysUpdateScreen;
  702. ClearScreen : @SysClearScreen;
  703. SetVideoMode : @SysSetVideoMode;
  704. GetVideoModeCount : @SysGetVideoModeCount;
  705. GetVideoModeData : @SysGetVideoModeData;
  706. SetCursorPos : @SysSetCursorPos;
  707. GetCursorType : @SysGetCursorType;
  708. SetCursorType : @SysSetCursorType;
  709. GetCapabilities : @SysGetCapabilities
  710. );
  711. initialization
  712. SetVideoDriver(SysVideoDriver);
  713. LastT := 50;
  714. LastL := 50;
  715. LastW := 80;
  716. LastH := 25;
  717. {$ifdef WITHBUFFERING}
  718. BufRp := CreateRastPort;
  719. BufRp^.Layer := nil;
  720. BufRp^.Bitmap := nil;
  721. {$endif}
  722. finalization
  723. {$ifdef WITHBUFFERING}
  724. if Assigned(BufRp^.Bitmap) then
  725. FreeBitmap(BufRp^.Bitmap);
  726. FreeRastPort(BufRp);
  727. {$endif}
  728. end.