x11dga1displayi.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. {$IFDEF ENABLE_X11_EXTENSION_XF86DGA1}
  2. Constructor TX11DGA1Display.Create(ADisplay : PDisplay; AScreen : Integer; Const AFlags : TX11Flags);
  3. Var
  4. dummy1, dummy2 : Integer;
  5. Begin
  6. Inherited;
  7. LOG('trying to create a DGA 1.0 display');
  8. FInDirect := False;
  9. FInMode := False;
  10. FModeInfo := Nil;
  11. { Check if we are root }
  12. If fpgeteuid <> 0 Then
  13. Raise TPTCError.Create('Have to be root to switch to DGA mode');
  14. { Check if the DGA extension and VidMode extension can be used }
  15. If Not XF86DGAQueryExtension(FDisplay, @dummy1, @dummy2) Then
  16. Raise TPTCError.Create('DGA extension not available');
  17. If Not XF86VidModeQueryExtension(FDisplay, @dummy1, @dummy2) Then
  18. Raise TPTCError.Create('VidMode extension not available');
  19. End;
  20. Destructor TX11DGA1Display.Destroy;
  21. Begin
  22. Close;
  23. Inherited Destroy;
  24. End;
  25. Procedure TX11DGA1Display.Open(ATitle : String; AWidth, AHeight : Integer; Const AFormat : TPTCFormat);
  26. Var
  27. vml : PXF86VidModeModeLine;
  28. dotclock : Integer;
  29. i : Integer;
  30. root : TWindow;
  31. e : TXEvent;
  32. found : Boolean;
  33. tmpArea : TPTCArea;
  34. r, g, b : Single;
  35. found_mode : Integer;
  36. min_diff : Integer;
  37. d_x, d_y : Integer;
  38. Begin
  39. FWidth := AWidth;
  40. FHeight := AHeight;
  41. { Get all availabe video modes }
  42. XF86VidModeGetAllModeLines(FDisplay, FScreen, @FModeInfoNum, @FModeInfo);
  43. FPreviousMode := -1;
  44. { Save previous mode }
  45. New(vml);
  46. Try
  47. XF86VidModeGetModeLine(FDisplay, FScreen, @dotclock, vml);
  48. Try
  49. For i := 0 To FModeInfoNum - 1 Do
  50. Begin
  51. If (vml^.hdisplay = FModeInfo[i]^.hdisplay) And
  52. (vml^.vdisplay = FModeInfo[i]^.vdisplay) Then
  53. Begin
  54. FPreviousMode := i;
  55. Break;
  56. End;
  57. End;
  58. Finally
  59. If vml^.privsize <> 0 Then
  60. XFree(vml^.c_private);
  61. End;
  62. Finally
  63. Dispose(vml);
  64. End;
  65. If FPreviousMode = -1 Then
  66. Raise TPTCError.Create('Current mode not found in modelist?! Err, this shouldn''t happen :)');
  67. { Find a video mode to set }
  68. { Normal modesetting first, find exactly matching mode }
  69. found_mode := -1;
  70. For i := 0 To FModeInfoNum - 1 Do
  71. If (FModeInfo[i]^.hdisplay = AWidth) And (FModeInfo[i]^.vdisplay = AHeight) Then
  72. Begin
  73. found_mode := i;
  74. Break;
  75. End;
  76. { Try to find a mode that matches the width first }
  77. If found_mode = -1 Then
  78. For i := 0 To FModeInfoNum - 1 Do
  79. If (FModeInfo[i]^.hdisplay = AWidth) And
  80. (FModeInfo[i]^.vdisplay >= AHeight) Then
  81. Begin
  82. found_mode := i;
  83. Break;
  84. End;
  85. { Next try to match the height }
  86. If found_mode = -1 Then
  87. For i := 0 To FModeInfoNum - 1 Do
  88. If (FModeInfo[i]^.hdisplay >= AWidth) And
  89. (FModeInfo[i]^.vdisplay = AHeight) Then
  90. Begin
  91. found_mode := i;
  92. Break;
  93. End;
  94. If found_mode = -1 Then
  95. Begin
  96. { Finally, find the mode that is bigger than the requested one and makes }
  97. { the least difference }
  98. min_diff := 987654321;
  99. For i := 0 To FModeInfoNum - 1 Do
  100. If (FModeInfo[i]^.hdisplay >= AWidth) And (FModeInfo[i]^.vdisplay >= AHeight) Then
  101. Begin
  102. d_x := Sqr(FModeInfo[i]^.hdisplay - AWidth);
  103. d_y := Sqr(FModeInfo[i]^.vdisplay - AHeight);
  104. If (d_x + d_y) < min_diff Then
  105. Begin
  106. min_diff := d_x + d_y;
  107. found_mode := i;
  108. End;
  109. End;
  110. End;
  111. If found_mode = -1 Then
  112. Raise TPTCError.Create('Cannot find a video mode to use');
  113. If Not XF86VidModeSwitchToMode(FDisplay, FScreen, FModeInfo[found_mode]) Then
  114. Raise TPTCError.Create('Error switching to requested video mode');
  115. FDestX := (FModeInfo[found_mode]^.hdisplay Div 2) - (AWidth Div 2);
  116. FDestY := (FModeInfo[found_mode]^.vdisplay Div 2) - (AHeight Div 2);
  117. XFlush(FDisplay);
  118. FInMode := True;
  119. { Check if the requested colour mode is available }
  120. FFormat := GetX11Format(AFormat);
  121. { Grab exclusive control over the keyboard and mouse }
  122. root := XRootWindow(FDisplay, FScreen);
  123. XGrabKeyboard(FDisplay, root, True, GrabModeAsync, GrabModeAsync, CurrentTime);
  124. XGrabPointer(FDisplay, root, True, PointerMotionMask Or ButtonPressMask Or
  125. ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None,
  126. CurrentTime);
  127. XFlush(FDisplay);
  128. { Get Display information }
  129. XF86DGAGetVideo(FDisplay, FScreen, @FDGAAddr, @FDGALineWidth,
  130. @FDGABankSize, @FDGAMemSize);
  131. { Don't have to be root anymore }
  132. { fpsetuid(fpgetuid);...}
  133. XF86DGAGetViewPortSize(FDisplay, FScreen, @FDGAWidth, @FDGAHeight);
  134. If XF86DGAForkApp(FScreen) <> 0 Then
  135. Raise TPTCError.Create('cannot do safety fork');
  136. If XF86DGADirectVideo(FDisplay, FScreen, XF86DGADirectGraphics Or
  137. XF86DGADirectKeyb Or XF86DGADirectMouse) = 0 Then
  138. Raise TPTCError.Create('cannot switch to DGA mode');
  139. FInDirect := True;
  140. FillChar(FDGAAddr^, FDGALineWidth * FDGAHeight * (FFormat.Bits Div 8), 0);
  141. XSelectInput(FDisplay, DefaultRootWindow(FDisplay),
  142. KeyPressMask Or KeyReleaseMask);
  143. XF86DGASetViewPort(FDisplay, FScreen, 0, 0); { Important.. sort of =) }
  144. found := False;
  145. Repeat
  146. { Stupid loop. The key }
  147. { events were causing }
  148. { problems.. }
  149. found := XCheckMaskEvent(FDisplay, KeyPressMask Or KeyReleaseMask, @e);
  150. Until Not found;
  151. { Create colour map in 8 bit mode }
  152. If FFormat.Bits = 8 Then
  153. Begin
  154. FColours := GetMem(256 * SizeOf(TXColor));
  155. If FColours = Nil Then
  156. Raise TPTCError.Create('Cannot allocate colour map cells');
  157. FCMap := XCreateColormap(FDisplay, RootWindow(FDisplay, FScreen),
  158. DefaultVisual(FDisplay, FScreen), AllocAll);
  159. If FCMap = 0 Then
  160. Raise TPTCError.Create('Cannot create colour map');
  161. End
  162. Else
  163. FCMap := 0;
  164. { Set 332 palette, for now }
  165. If (FFormat.Bits = 8) And FFormat.Direct Then
  166. Begin
  167. {Taken from PTC 0.72, i hope it's fine}
  168. For i := 0 To 255 Do
  169. Begin
  170. r := ((i And $E0) Shr 5) * 255 / 7;
  171. g := ((i And $1C) Shr 2) * 255 / 7;
  172. b := (i And $03) * 255 / 3;
  173. FColours[i].pixel := i;
  174. FColours[i].red := Round(r) Shl 8;
  175. FColours[i].green := Round(g) Shl 8;
  176. FColours[i].blue := Round(b) Shl 8;
  177. Byte(FColours[i].flags) := DoRed Or DoGreen Or DoBlue;
  178. End;
  179. XStoreColors(FDisplay, FCMap, FColours, 256);
  180. XF86DGAInstallColormap(FDisplay, FScreen, FCMap);
  181. End;
  182. { Set clipping area }
  183. tmpArea := TPTCArea.Create(0, 0, FWidth, FHeight);
  184. Try
  185. FClip.Assign(tmpArea);
  186. Finally
  187. tmpArea.Free;
  188. End;
  189. End;
  190. { Not in DGA mode }
  191. Procedure TX11DGA1Display.Open(AWindow : TWindow; Const AFormat : TPTCFormat);
  192. Begin
  193. If AWindow = 0 Then; { Prevent warnings }
  194. If AFormat = Nil Then;
  195. End;
  196. Procedure TX11DGA1Display.Open(AWindow : TWindow; Const AFormat : TPTCFormat; AX, AY, AWidth, AHeight : Integer);
  197. Begin
  198. If (AWindow = 0) Or
  199. (AFormat = Nil) Or
  200. (AX = 0) Or
  201. (AY = 0) Or
  202. (AWidth = 0) Or
  203. (AHeight = 0) Then;
  204. End;
  205. Procedure TX11DGA1Display.Close;
  206. Begin
  207. If FInDirect Then
  208. Begin
  209. FInDirect := False;
  210. XF86DGADirectVideo(FDisplay, FScreen, 0);
  211. End;
  212. If FInMode Then
  213. Begin
  214. FInMode := False;
  215. XF86VidModeSwitchToMode(FDisplay, FScreen, FModeInfo[FPreviousMode]);
  216. XUngrabKeyboard(FDisplay, CurrentTime);
  217. XUngrabPointer(FDisplay, CurrentTime);
  218. End;
  219. If FDisplay <> Nil Then
  220. XFlush(FDisplay);
  221. If FCMap <> 0 Then
  222. Begin
  223. XFreeColormap(FDisplay, FCMap);
  224. FCMap := 0;
  225. End;
  226. FreeMemAndNil(FColours);
  227. If FModeInfo <> Nil Then
  228. Begin
  229. XFree(FModeInfo);
  230. FModeInfo := Nil;
  231. End;
  232. End;
  233. Procedure TX11DGA1Display.GetModes(Var AModes : TPTCModeDynArray);
  234. Begin
  235. SetLength(AModes, 1);
  236. AModes[0] := TPTCMode.Create;
  237. {todo...}
  238. End;
  239. Procedure TX11DGA1Display.Update;
  240. Begin
  241. End;
  242. Procedure TX11DGA1Display.Update(Const AArea : TPTCArea);
  243. Begin
  244. End;
  245. Procedure TX11DGA1Display.HandleEvents;
  246. Var
  247. e : TXEvent;
  248. NewFocus : Boolean;
  249. NewFocusSpecified : Boolean;
  250. Function UsefulEventsPending : Boolean;
  251. Var
  252. tmpEvent : TXEvent;
  253. Begin
  254. If XCheckTypedEvent(FDisplay, ClientMessage, @tmpEvent) Then
  255. Begin
  256. Result := True;
  257. XPutBackEvent(FDisplay, @tmpEvent);
  258. Exit;
  259. End;
  260. If XCheckMaskEvent(FDisplay, FocusChangeMask Or
  261. KeyPressMask Or KeyReleaseMask Or
  262. ButtonPressMask Or ButtonReleaseMask Or
  263. PointerMotionMask Or ExposureMask, @tmpEvent) Then
  264. Begin
  265. Result := True;
  266. XPutBackEvent(FDisplay, @tmpEvent);
  267. Exit;
  268. End;
  269. Result := False;
  270. End;
  271. Procedure HandleKeyEvent;
  272. Var
  273. sym : TKeySym;
  274. sym_modded : TKeySym; { modifiers like shift are taken into account here }
  275. press : Boolean;
  276. alt, shift, ctrl : Boolean;
  277. uni : Integer;
  278. key : TPTCKeyEvent;
  279. buf : Array[1..16] Of Char;
  280. Begin
  281. sym := XLookupKeySym(@e.xkey, 0);
  282. XLookupString(@e.xkey, @buf, SizeOf(buf), @sym_modded, Nil);
  283. uni := X11ConvertKeySymToUnicode(sym_modded);
  284. alt := (e.xkey.state And Mod1Mask) <> 0;
  285. shift := (e.xkey.state And ShiftMask) <> 0;
  286. ctrl := (e.xkey.state And ControlMask) <> 0;
  287. If e._type = KeyPress Then
  288. press := True
  289. Else
  290. press := False;
  291. key := Nil;
  292. Case sym Shr 8 Of
  293. 0 : key := TPTCKeyEvent.Create(FNormalKeys[sym And $FF], uni, alt, shift, ctrl, press);
  294. $FF : key := TPTCKeyEvent.Create(FFunctionKeys[sym And $FF], uni, alt, shift, ctrl, press);
  295. Else
  296. key := TPTCKeyEvent.Create;
  297. End;
  298. FEventQueue.AddEvent(key);
  299. End;
  300. Begin
  301. NewFocusSpecified := False;
  302. While UsefulEventsPending Do
  303. Begin
  304. XNextEvent(FDisplay, @e);
  305. Case e._type Of
  306. FocusIn : Begin
  307. NewFocus := True;
  308. NewFocusSpecified := True;
  309. End;
  310. FocusOut : Begin
  311. NewFocus := False;
  312. NewFocusSpecified := True;
  313. End;
  314. ClientMessage : Begin
  315. { If (e.xclient.format = 32) And (TAtom(e.xclient.data.l[0]) = m_atom_close) Then
  316. Halt(0);}
  317. End;
  318. Expose : Begin
  319. {...}
  320. End;
  321. KeyPress, KeyRelease : HandleKeyEvent;
  322. ButtonPress, ButtonRelease : Begin
  323. {...}
  324. End;
  325. MotionNotify : Begin
  326. {...}
  327. End;
  328. End;
  329. End;
  330. // HandleChangeFocus(NewFocus);
  331. End;
  332. Function TX11DGA1Display.NextEvent(Var AEvent : TPTCEvent; AWait : Boolean; Const AEventMask : TPTCEventMask) : Boolean;
  333. Var
  334. tmpEvent : TXEvent;
  335. Begin
  336. FreeAndNil(AEvent);
  337. Repeat
  338. { process all events from the X queue and put them on our FEventQueue }
  339. HandleEvents;
  340. { try to find an event that matches the EventMask }
  341. AEvent := FEventQueue.NextEvent(AEventMask);
  342. If AWait And (AEvent = Nil) Then
  343. Begin
  344. { if the X event queue is empty, block until an event is received }
  345. XPeekEvent(FDisplay, @tmpEvent);
  346. End;
  347. Until (Not AWait) Or (AEvent <> Nil);
  348. Result := AEvent <> Nil;
  349. End;
  350. Function TX11DGA1Display.PeekEvent(AWait : Boolean; Const AEventMask : TPTCEventMask) : TPTCEvent;
  351. Var
  352. tmpEvent : TXEvent;
  353. Begin
  354. Repeat
  355. { process all events from the X queue and put them on our FEventQueue }
  356. HandleEvents;
  357. { try to find an event that matches the EventMask }
  358. Result := FEventQueue.PeekEvent(AEventMask);
  359. If AWait And (Result = Nil) Then
  360. Begin
  361. { if the X event queue is empty, block until an event is received }
  362. XPeekEvent(FDisplay, @tmpEvent);
  363. End;
  364. Until (Not AWait) Or (Result <> Nil);
  365. End;
  366. Function TX11DGA1Display.Lock : Pointer;
  367. Begin
  368. Result := FDGAAddr + FDGALineWidth * FDestY * (FFormat.Bits Div 8) +
  369. FDestX * (FFormat.Bits Div 8);
  370. End;
  371. Procedure TX11DGA1Display.Unlock;
  372. Begin
  373. End;
  374. Procedure TX11DGA1Display.Palette(Const APalette : TPTCPalette);
  375. Var
  376. pal : PUint32;
  377. i : Integer;
  378. Begin
  379. pal := APalette.data;
  380. If Not FFormat.Indexed Then
  381. Exit;
  382. For i := 0 To 255 Do
  383. Begin
  384. FColours[i].pixel := i;
  385. FColours[i].red := ((pal[i] Shr 16) And $FF) Shl 8;
  386. FColours[i].green := ((pal[i] Shr 8) And $FF) Shl 8;
  387. FColours[i].blue := (pal[i] And $FF) Shl 8;
  388. Byte(FColours[i].flags) := DoRed Or DoGreen Or DoBlue;
  389. End;
  390. XStoreColors(FDisplay, FCMap, FColours, 256);
  391. XF86DGAInstallColormap(FDisplay, FScreen, FCMap);
  392. End;
  393. Function TX11DGA1Display.GetPitch : Integer;
  394. Begin
  395. Result := FDGALineWidth * (FFormat.Bits Div 8);
  396. End;
  397. Function TX11DGA1Display.GetX11Window : TWindow;
  398. Begin
  399. Result := DefaultRootWindow(FDisplay);
  400. End;
  401. Function TX11DGA1Display.IsFullScreen : Boolean;
  402. Begin
  403. { DGA is always fullscreen }
  404. Result := True;
  405. End;
  406. Procedure TX11DGA1Display.SetCursor(AVisible : Boolean);
  407. Begin
  408. {nothing... raise exception if visible=true?}
  409. End;
  410. {$ENDIF ENABLE_X11_EXTENSION_XF86DGA1}