2
// This unit is part of the GLScene Engine https://github.com/glscene
5
Routines to interact with the screen/desktop.
9
// screen - This units contains routines to interact with the screen/desktop.
11
// Last Change - 30. September 1998
12
// for more information see help file
19
{$IFDEF MSWINDOWS} Windows, {$ENDIF}
20
{$IFDEF GLS_X11_SUPPORT} x, xlib, xf86vmode, {$ENDIF}
22
Classes, GLVectorGeometry, GLCrossPlatform;
30
TResolution = 0 .. MaxVideoModes;
33
TWindowAttribute = (woDesktop, woStayOnTop, woTransparent);
34
TWindowAttributes = set of TWindowAttribute;
36
// window-to-screen fitting
37
TWindowFitting = (wfDefault, wfFitWindowToScreen, wfFitScreenToWindow);
41
TGLDisplayOptions = class(TPersistent)
44
FScreenResolution: TResolution;
45
FWindowAttributes: TWindowAttributes;
46
FWindowFitting: TWindowFitting;
48
procedure Assign(Source: TPersistent); override;
50
property FullScreen: Boolean read FFullScreen write FFullScreen
52
property ScreenResolution: TResolution read FScreenResolution
53
write FScreenResolution default 0;
54
property WindowAttributes: TWindowAttributes read FWindowAttributes
55
write FWindowAttributes default [];
56
property WindowFitting: TWindowFitting read FWindowFitting
57
write FWindowFitting default wfDefault;
60
TVideoMode = packed record
68
PVideoMode = ^TVideoMode;
70
function GetIndexFromResolution(XRes, YRes, BPP: Integer): TResolution;
72
procedure ReadVideoModes;
74
// : Changes to the video mode given by 'Index'
75
function SetFullscreenMode(modeIndex: TResolution;
76
displayFrequency: Integer = 0): Boolean;
79
procedure ReadScreenImage(Dest: HDC; DestLeft, DestTop: Integer;
82
procedure RestoreDefaultMode;
84
procedure GLShowCursor(AShow: Boolean);
85
procedure GLSetCursorPos(AScreenX, AScreenY: Integer);
86
procedure GLGetCursorPos(var point: TGLPoint);
87
function GLGetScreenWidth: Integer;
88
function GLGetScreenHeight: Integer;
91
vNumberVideoModes: Integer = 0;
92
vCurrentVideoMode: Integer = 0;
94
vVideoModes: array of TVideoMode;
96
{$IFDEF GLS_X11_SUPPORT}
98
vScreenModeChanged: Boolean;
99
vVideoModes: array of PXF86VidModeModeInfo;
100
vDesktop: TXF86VidModeModeInfo;
103
// ------------------------------------------------------------------------------
104
// ------------------------------------------------------------------------------
105
// ------------------------------------------------------------------------------
108
// ------------------------------------------------------------------------------
109
// ------------------------------------------------------------------------------
110
// ------------------------------------------------------------------------------
117
TLowResMode = packed record
124
NumberLowResModes = 15;
126
LowResModes: array [0 .. NumberLowResModes - 1] of TLowResMode = ((Width: 320;
127
Height: 200; ColorDepth: 8), (Width: 320; Height: 200; ColorDepth: 15),
128
(Width: 320; Height: 200; ColorDepth: 16), (Width: 320; Height: 200;
129
ColorDepth: 24), (Width: 320; Height: 200; ColorDepth: 32), (Width: 400;
130
Height: 300; ColorDepth: 8), (Width: 400; Height: 300; ColorDepth: 15),
131
(Width: 400; Height: 300; ColorDepth: 16), (Width: 400; Height: 300;
132
ColorDepth: 24), (Width: 400; Height: 300; ColorDepth: 32), (Width: 512;
133
Height: 384; ColorDepth: 8), (Width: 512; Height: 384; ColorDepth: 15),
134
(Width: 512; Height: 384; ColorDepth: 16), (Width: 512; Height: 384;
135
ColorDepth: 24), (Width: 512; Height: 384; ColorDepth: 32));
140
procedure TGLDisplayOptions.Assign(Source: TPersistent);
142
if Source is TGLDisplayOptions then
144
FFullScreen := TGLDisplayOptions(Source).FFullScreen;
145
FScreenResolution := TGLDisplayOptions(Source).FScreenResolution;
146
FWindowAttributes := TGLDisplayOptions(Source).FWindowAttributes;
147
FWindowFitting := TGLDisplayOptions(Source).FWindowFitting;
150
inherited Assign(Source);
153
// GetIndexFromResolution
155
function GetIndexFromResolution(XRes, YRes, BPP: Integer): TResolution;
157
// Determines the index of a screen resolution nearest to the
158
// given values. The returned screen resolution is always greater
159
// or equal than XRes and YRes or, in case the resolution isn't
160
// supported, the value 0, which indicates the default mode.
164
XDiff, YDiff: Integer;
170
// prepare result in case we don't find a valid mode
172
// set differences to maximum
178
for I := 1 to vNumberVideoModes - 1 do
180
with vVideoModes[I] do
182
if (Width >= XRes) and ((Width - XRes) <= XDiff) and (Height >= YRes) and
183
((Height - YRes) <= YDiff) and (ColorDepth >= BPP) and
184
((ColorDepth - BPP) <= CDiff) then
186
XDiff := Width - XRes;
187
YDiff := Height - YRes;
188
CDiff := ColorDepth - BPP;
193
{$IFDEF GLS_X11_SUPPORT}
194
with vVideoModes[I]^ do
196
if (hDisplay >= XRes) and ((hDisplay - XRes) <= XDiff) and
197
(vDisplay >= YRes) and ((vDisplay - YRes) <= YDiff) then
199
XDiff := hDisplay - XRes;
200
YDiff := vDisplay - YRes;
207
{$MESSAGE Warn 'Needs to be implemented'}
217
procedure TryToAddToList(deviceMode: TDevMode);
218
// Adds a video mode to the list if it's not a duplicate and can actually be set.
223
// See if this is a duplicate mode (can happen because of refresh
224
// rates, or because we explicitly try all the low-res modes)
225
for I := 1 to vNumberVideoModes - 1 do
228
vm := @vVideoModes[I];
229
if ((dmBitsPerPel = vm^.ColorDepth) and (dmPelsWidth = vm^.Width) and
230
(dmPelsHeight = vm^.Height)) then
232
// it's a duplicate mode, higher frequency?
233
if dmDisplayFrequency > vm^.MaxFrequency then
234
vm^.MaxFrequency := dmDisplayFrequency;
239
// do a mode set test (doesn't actually do the mode set, but reports whether it would have succeeded).
240
if ChangeDisplaySettings(deviceMode, CDS_TEST or CDS_FULLSCREEN) <> DISP_CHANGE_SUCCESSFUL
244
// it's a new, valid mode, so add this to the list
245
vm := @vVideoModes[vNumberVideoModes];
248
vm^.ColorDepth := dmBitsPerPel;
249
vm^.Width := dmPelsWidth;
250
vm^.Height := dmPelsHeight;
251
vm^.MaxFrequency := dmDisplayFrequency;
252
vm^.Description := Format('%d x %d, %d bpp', [dmPelsWidth, dmPelsHeight,
255
Inc(vNumberVideoModes);
257
{$IFDEF GLS_X11_SUPPORT}
259
procedure TryToAddToList(); // Without input parameters.
261
XF86VidModeGetAllModeLines(vDisplay, vCurrentVideoMode, @vNumberVideoModes,
266
procedure TryToAddToList(); // Without input parameters.
268
{$MESSAGE Warn 'Needs to be implemented'}
274
procedure ReadVideoModes;
277
I, ModeNumber: Integer;
279
deviceMode: TDevMode;
282
if vNumberVideoModes > 0 then
285
SetLength(vVideoModes, MaxVideoModes);
286
vNumberVideoModes := 1;
288
// prepare 'default' entry
290
with vVideoModes[0] do
292
ColorDepth := GetDeviceCaps(DeskDC, BITSPIXEL) *
293
GetDeviceCaps(DeskDC, PLANES);
294
Width := Screen.Width;
295
Height := Screen.Height;
296
Description := 'default';
298
ReleaseDC(0, DeskDC);
301
// enumerate all available video modes
304
done := not EnumDisplaySettings(nil, ModeNumber, deviceMode);
305
TryToAddToList(deviceMode);
307
until (done or (vNumberVideoModes >= MaxVideoModes));
309
// low-res modes don't always enumerate, ask about them explicitly
315
dmFields := DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT;
316
// make sure the driver doesn't just answer yes to all tests
317
if ChangeDisplaySettings(deviceMode, CDS_TEST or CDS_FULLSCREEN) <> DISP_CHANGE_SUCCESSFUL
321
while (I < NumberLowResModes - 1) and
322
(vNumberVideoModes < MaxVideoModes) do
324
dmSize := Sizeof(deviceMode);
325
with LowResModes[I] do
327
dmBitsPerPel := ColorDepth;
328
dmPelsWidth := Width;
329
dmPelsHeight := Height;
331
dmFields := DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT;
332
TryToAddToList(deviceMode);
338
{$IFDEF GLS_X11_SUPPORT}
342
SetLength(vVideoModes, MaxVideoModes);
343
// if error usr/bin/ld: cannot find -lXxf86vm
344
// then sudo apt-get install libXxf86vm-dev
346
// Connect to XServer
347
vDisplay := XOpenDisplay(nil);
348
if not Assigned(vDisplay) Then
349
Assert(False, 'Not conected with X Server');
350
vCurrentVideoMode := DefaultScreen(vDisplay);
352
// Check support XF86VidMode Extension
353
// {$IF (FPC_VERSION = 2) and (FPC_RELEASE < 5)}
354
// if XF86VidModeQueryExtension( vDisplay, @i, @j )=0 then
356
if not XF86VidModeQueryExtension(vDisplay, @I, @j) then
358
Assert(False, 'XF86VidMode Extension not support');
360
// Get Current Settings
361
if not vScreenModeChanged then
362
if XF86VidModeGetModeLine(vDisplay, vCurrentVideoMode,
363
@vDesktop.dotclock, PXF86VidModeModeLine(PtrUInt(@vDesktop) +
364
Sizeof(vDesktop.dotclock))) then
366
XCloseDisplay(vDisplay);
370
{$MESSAGE Warn 'ReadVideoModes not yet implemented for Darwin platforms'}
376
function SetFullscreenMode(modeIndex: TResolution;
377
displayFrequency: Integer = 0): Boolean;
380
deviceMode: TDevMode;
383
FillChar(deviceMode, Sizeof(deviceMode), 0);
386
dmSize := Sizeof(deviceMode);
387
dmBitsPerPel := vVideoModes[modeIndex].ColorDepth;
388
dmPelsWidth := vVideoModes[modeIndex].Width;
389
dmPelsHeight := vVideoModes[modeIndex].Height;
390
dmFields := DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT;
391
if displayFrequency > 0 then
393
dmFields := dmFields or DM_DISPLAYFREQUENCY;
394
if displayFrequency > vVideoModes[modeIndex].MaxFrequency then
395
displayFrequency := vVideoModes[modeIndex].MaxFrequency;
396
dmDisplayFrequency := displayFrequency;
399
Result := ChangeDisplaySettings(deviceMode, CDS_FULLSCREEN)
400
= DISP_CHANGE_SUCCESSFUL;
402
vCurrentVideoMode := modeIndex;
404
{$IFDEF GLS_X11_SUPPORT}
406
vSettings: TXF86VidModeModeInfo;
410
vDisplay := XOpenDisplay(nil);
411
vSettings := vVideoModes[modeIndex]^;
412
if (vSettings.hDisplay <> vDesktop.hDisplay) and
413
(vSettings.vDisplay <> vDesktop.vDisplay) then
416
// vsettings.vtotal:=vsettings.vdisplay;
417
XF86VidModeSwitchToMode(vDisplay, vCurrentVideoMode, @vSettings);
418
XF86VidModeSetViewPort(vDisplay, vCurrentVideoMode, 0, 0);
419
wnd := XDefaultRootWindow(vDisplay);
420
XGrabPointer(vDisplay, wnd, true,
421
PointerMotionMask + ButtonReleaseMask, GrabModeAsync,
422
GrabModeAsync, wnd, none, 0);
423
vScreenModeChanged := true;
428
XF86VidModeSwitchToMode(vDisplay, vCurrentVideoMode, @vDesktop);
429
vScreenModeChanged := False;
431
// Disconnect to XServer else settings not accept
432
XCloseDisplay(vDisplay);
433
Result := vScreenModeChanged;
437
{$MESSAGE Warn 'Needs to be implemented'}
445
procedure ReadScreenImage(Dest: HDC; DestLeft, DestTop: Integer;
446
SrcRect: TRectangle);
450
screenDC := GetDC(0);
453
BitBlt(Dest, DestLeft, DestTop, SrcRect.Width, SrcRect.Height,
454
screenDC, SrcRect.Left, SrcRect.Top, SRCCOPY);
456
ReleaseDC(0, screenDC);
461
// RestoreDefaultMode
463
procedure RestoreDefaultMode;
469
ChangeDisplaySettings(t^, CDS_FULLSCREEN);
471
{$IFDEF GLS_X11_SUPPORT}
473
// if vCurrentVideoMode=0 then
475
vDisplay := XOpenDisplay(nil);
476
XF86VidModeSwitchToMode(vDisplay, vCurrentVideoMode, @vDesktop);
477
vScreenModeChanged := False;
478
XCloseDisplay(vDisplay);
482
{$MESSAGE Warn 'Needs to be implemented'}
486
procedure GLShowCursor(AShow: Boolean);
492
{$MESSAGE Warn 'ShowCursor: Needs to be implemented'}
493
// Use Form.Cursor:=crNone
497
procedure GLSetCursorPos(AScreenX, AScreenY: Integer);
500
SetCursorPos(AScreenX, AScreenY);
502
{$IFDEF GLS_X11_SUPPORT}
507
dpy := XOpenDisplay(nil);
508
root := RootWindow(dpy, DefaultScreen(dpy));
509
XWarpPointer(dpy, none, root, 0, 0, 0, 0, AScreenX,
515
{$MESSAGE Warn 'Needs to be implemented'}
519
procedure GLGetCursorPos(var point: TGLPoint);
524
{$IFDEF GLS_X11_SUPPORT}
527
root, child: TWindow;
528
rootX, rootY, winX, winY: Integer;
534
dpy := XOpenDisplay(nil);
536
(XQueryPointer(dpy, XDefaultRootWindow(dpy), @root,
537
@child, @rootX, @rootY, @winX, @winY, @xstate));
547
{$MESSAGE Warn 'Needs to be implemented'}
551
function GLGetScreenWidth: Integer;
553
Result := Screen.Width;
556
function GLGetScreenHeight: Integer;
558
Result := Screen.Height;
561
// ------------------------------------------------------------------
562
// ------------------------------------------------------------------
563
// ------------------------------------------------------------------
566
// ------------------------------------------------------------------
567
// ------------------------------------------------------------------
568
// ------------------------------------------------------------------
573
if vCurrentVideoMode <> 0 then
575
{$IFDEF GLS_X11_SUPPORT}
576
if vScreenModeChanged then
578
RestoreDefaultMode; // set default video mode