Windows2000/private/windows/opengl/scrsave/common/glscrnsv.cxx
2020-09-30 17:12:32 +02:00

806 lines
19 KiB
C++

/**Module*Header**\
* Module Name: glscrnsv.c
* Companion file to scrnsave.c. Hooks out any changes in functionality
* defined as GL_SCRNSAVE in scrnsave.c, and does general intialization.
* Copyright (c) 1996 Microsoft Corporation
\**/
#include <windows.h>
#include <windowsx.h>
#include <stdlib.h>
#include "scrnsave.h"
#include "glscrnsv.h"
#include "ssintrnl.hxx"
#include "sswindow.hxx"
#include "glscrnsv.hxx"
#include "sswproc.hxx"
static UINT (*KeyDownFunc)(int) = NULL;
// Global ptr to screen saver instance
SCRNSAVE *gpss = NULL;
// Global strings.
#define GEN_STRING_SIZE 64
TCHAR szScreenSaverTitle[GEN_STRING_SIZE];
LPCTSTR pszWindowClass = TEXT("WindowsScreenSaverClass"); // main class name
LPCTSTR pszChildWindowClass = TEXT("ScreenSaverClass"); // child class name
// forward declarations of internal fns
static BOOL RegisterMainClass( WNDPROC wndProc, HBRUSH hbrBg, HCURSOR hCursor );
static BOOL RegisterChildClass();
static BOOL AttemptResolutionSwitch( int width, int height, ISIZE *pNewSize );
// externs
extern void InitRealScreenSave(); // scrnsave.cxx
extern LRESULT WINAPI
RealScreenSaverProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
extern VOID UnloadPwdDLL(VOID);
extern BOOL GLScreenSaverConfigureDialog( HWND hDlg, UINT msg, WPARAM wParam,
LPARAM lParam ); // sswproc.cxx
#ifdef SS_INITIAL_CLEAR
static void InitialClear( PSSW *pssw );
#endif
/**\
* GLDoScreenSave
* Runs the screen saver in the specified mode
* GL version of DoScreenSave in scrnsave.c
* Does basic init, creates initial set of windows, and starts the message
* loop, which runs until terminated by some event.
\**/
static INT_PTR
GLDoScreenSave( int winType, LPARAM lParam )
{
MSG msg;
// Create screen saver instance - this calls ss_Init()
SCRNSAVE ss( winType, lParam );
// Setup all the windows and start the message loop
if( ss.SetupInitialWindows() )
{
// Send message to main window to start the drawing timer
#ifdef SS_DELAYED_START_KLUGE
// Kluge to work around 'window-not-ready' problem in child
// preview mode - trigger off of WM_PAINT instead
if( ! SS_DELAY_START(winType) )
SendMessage( ss.psswMain->hwnd, SS_WM_START, 0, 0 );
#else
SendMessage( ss.psswMain->hwnd, SS_WM_START, 0, 0 );
#endif // SS_DELAYED_START_KLUGE
while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
// We're done - screen saver exiting.
// free password-handling DLL if loaded
UnloadPwdDLL();
return msg.wParam;
}
/**\
* SCRNSAVE constructors
\**/
SCRNSAVE::SCRNSAVE( int typeArg, LPARAM lParam )
: type( typeArg ), initParam( lParam )
{
Init();
}
SCRNSAVE::SCRNSAVE( int typeArg )
: type(typeArg)
{
initParam = 0;
Init();
}
void
SCRNSAVE::Init()
{
psswMain = NULL;
psswGL = NULL;
bResSwitch = FALSE;
pssc = NULL;
pssPal = NULL;
flags = 0;
#ifdef SS_DEBUG
bDoTiming = type == SS_TYPE_NORMAL ? TRUE : FALSE;
#endif
// Global ptr to the screen saver instance
gpss = this;
// Platform detections
ss_QueryOSVersion();
// Initialize randomizer
ss_RandInit();
// Disable message boxes in GLAUX
tkErrorPopups(FALSE);
// Create multi-purpose black bg brush
hbrBg = (HBRUSH) GetStockObject( BLACK_BRUSH );
// Call client ss's init function, to get ptr to its configuration
// request
if( type == SS_TYPE_CONFIG ) {
// This case handled differently
return;
}
pssc = ss_Init();
SS_ASSERT( pssc, "SCRNSAVE constructor failure\n" );
// Set GL config structure from pssc
GLc.pfFlags = 0;
GLc.hrc = 0;
GLc.pStretch = NULL;
switch( pssc->depthType ) {
case SS_DEPTH16 :
GLc.pfFlags |= SS_DEPTH16_BIT;
break;
case SS_DEPTH32 :
GLc.pfFlags |= SS_DEPTH32_BIT;
break;
}
if( pssc->bDoubleBuf )
GLc.pfFlags |= SS_DOUBLEBUF_BIT;
if( pssc->bStretch )
GLc.pStretch = &pssc->stretchInfo;
}
/**\
* SetupInitialWindows
* Create / Configure all required windows.
\**/
BOOL
SCRNSAVE::SetupInitialWindows()
{
// Create the windows
if( ! CreateInitialWindows() ) {
SS_WARNING( "SCRNSAVE:: Couldn't create windows\n" );
return FALSE;
}
// Initial window clear
//mf: doesn't seem to be necessary now...
//#define SS_INITIAL_MAIN_WINDOW_CLEAR 1
#ifdef SS_INITIAL_MAIN_WINDOW_CLEAR
if( type == SS_TYPE_PREVIEW ) {
// Make sure the screen is cleared to black before we start drawing
// anything, as sometimes the background WM_PAINT doesn't get to us right
// away. This is only a problem in preview mode
psswMain->GdiClear();
}
#endif
// Configure and Init the windows, if applicable
#ifdef SS_DELAYED_START_KLUGE
// delay start for some configurations
if( ! SS_DELAY_START(type) ) {
SendMessage( psswMain->hwnd, SS_WM_INITGL, 0, 0 );
}
#else
SendMessage( psswMain->hwnd, SS_WM_INITGL, 0, 0 );
#endif // SS_DELAYED_START_KLUGE
return TRUE;
}
/**\
* CreateInitialWindows
* Create the intitial set of windows.
\**/
BOOL
SCRNSAVE::CreateInitialWindows()
{
PSSW pssw;
UINT uStyle;
UINT uExStyle;
LPCTSTR pszWindowTitle;
if( !pssc )
return FALSE;
// Handle any request for resolution change
#define SS_RESOLUTION_SWITCH 1
#ifdef SS_RESOLUTION_SWITCH
if( pssc->bStretch &&
(type == SS_TYPE_FULLSCREEN) &&
(GetSystemMetrics(SM_CMONITORS) == 1) )
{
STRETCH_INFO *pStretch = &pssc->stretchInfo;
ISIZE newSize;
// Try and change screen resolution to match stretch size
bResSwitch = AttemptResolutionSwitch( pStretch->baseWidth,
pStretch->baseHeight, &newSize );
// Is stretching still necessary if resolution changed ?
if( bResSwitch ) {
if( (newSize.width == pStretch->baseWidth) &&
(newSize.height == pStretch->baseHeight) )
// exact match, no stretching now necessary
pssc->bStretch = FALSE;
}
}
#endif
// Currently the bitmaps used in stretch mode don't support palette
// messages, so disable any stretching when in PREVIEW mode (where we
// need to support palette interaction).
// mf: actually this is only a consideration in 8-bit mode...
if( (type == SS_TYPE_PREVIEW) && pssc->bStretch )
pssc->bStretch = FALSE;
// Create the main ss window
if( ! CreateMainWindow() )
return FALSE;
#ifdef SS_INITIAL_CLEAR
// If main window is transparent, can do an initial clear here before
// any other windows are created or palettes modified
// This is bogus on NT, as system switches to secure desktop when screen
// saver kicks in automatically.
InitialClear( pssw );
#endif
// For now, simple window environment is described by pssc, so things
// like bFloater and bStretch are mutually exclusive.
SS_GL_CONFIG *pGLc = &gpss->GLc;
if( pssc->bFloater ) {
if( !(pssw = CreateChildWindow( &pssc->floaterInfo )) )
return FALSE;
pssw->pGLc = pGLc;
psswGL = pssw; // support old-style
} else {
psswMain->pGLc = pGLc;
psswGL = psswMain; // support old-style
}
return TRUE;
}
/**\
* NormalWindowScreenSaverProc
* Highest level window proc, used only in normal window (/w) mode.
\**/
LRESULT WINAPI
NormalWindowScreenSaverProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
{
case WM_SETTEXT:
// RealScreenSaverProc won't allow this - bypass it
return ScreenSaverProc( hWnd, uMsg, wParam, lParam );
case WM_CHAR:
if( KeyDownFunc ) {
int key = (int)wParam;
(*KeyDownFunc)(key);
}
break;
case WM_KEYDOWN:
if( wParam == VK_ESCAPE ) {
PostMessage( hWnd, WM_CLOSE, 0, 0l );
break;
} else if( KeyDownFunc ) {
(*KeyDownFunc)((int)wParam);
return 0;
}
return 0; // ??
default:
break;
}
return RealScreenSaverProc( hWnd, uMsg, wParam, lParam );
}
/**\
* DoScreenSave
* Hooked out version of DoScreenSave in standard scrnsave.c
\**/
INT_PTR
DoScreenSave( HWND hwndParent )
{
return GLDoScreenSave( hwndParent ? SS_TYPE_PREVIEW : SS_TYPE_FULLSCREEN,
(LPARAM) hwndParent );
}
/**\
* DoWindowedScreenSave
* Called when screen saver invoked with /w (window mode) parameter
\**/
INT_PTR
DoWindowedScreenSave( LPCTSTR szArgs )
{
return GLDoScreenSave( SS_TYPE_NORMAL, (LPARAM) szArgs );
}
/**\
* DoConfigBox
* Hooked out version of DoConfigBox in standard scrnsave.c
\**/
INT_PTR
DoConfigBox( HWND hwndParent )
{
// let the consumer register any special controls for the dialog
if( !RegisterDialogClasses( hMainInstance ) )
return FALSE;
// Create screen saver instance
SCRNSAVE ss( SS_TYPE_CONFIG );
int retVal = (int)DialogBox( hMainInstance,
MAKEINTRESOURCE( DLG_SCRNSAVECONFIGURE ),
hwndParent, (DLGPROC)GLScreenSaverConfigureDialog );
return retVal;
}
/**\
* CreateMainWindow
* Creates main screen saver window based on the window type
\**/
BOOL
SCRNSAVE::CreateMainWindow()
{
WNDPROC wndProc;
ISIZE size;
UINT uStyle = 0;
UINT uExStyle = 0;
IPOINT2D pos;
LPCTSTR pszWindowTitle;
HCURSOR hCursor = NULL;
HBRUSH hbrBgMain;
PSSW pssw;
BOOL bFailed;
HWND hwndParent = NULL;
int nx, ny; // window origin
int ncx, ncy; // window size
wndProc = RealScreenSaverProc;
switch( type ) {
case SS_TYPE_FULLSCREEN:
{
HWND hOther;
// Get origin and size of virtual desktop
nx = GetSystemMetrics( SM_XVIRTUALSCREEN );
ny = GetSystemMetrics( SM_YVIRTUALSCREEN );
ncx = GetSystemMetrics( SM_CXVIRTUALSCREEN );
ncy = GetSystemMetrics( SM_CYVIRTUALSCREEN );
//#define SS_FULLSCREEN_DEBUG 1
#ifdef SS_FULLSCREEN_DEBUG
// Reduce window size so we can see debugger
ncx >>= 1;
ncy >>= 1;
#endif
uStyle = WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
uExStyle = WS_EX_TOPMOST;
pszWindowTitle = TEXT("Screen Saver"); // MUST differ from preview
// if there is another NORMAL screen save instance, switch to it
hOther = FindWindow( pszWindowClass, pszWindowTitle );
if( hOther && IsWindow( hOther ) )
{
SS_DBGINFO( "SCRNSAVE::CreateMainWindow : Switching to other ss instance\n" );
SetForegroundWindow( hOther );
return FALSE;
}
InitRealScreenSave();
}
break;
case SS_TYPE_PREVIEW:
{
RECT rcParent;
hwndParent = (HWND) initParam;
GetClientRect( hwndParent, &rcParent );
fChildPreview = TRUE;
ncx = rcParent.right;
ncy = rcParent.bottom;
nx = 0;
ny = 0;
uStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN;
pszWindowTitle = TEXT("Preview"); // MUST differ from full screen
}
break;
case SS_TYPE_NORMAL:
{
// We set fChildPreview even when we're running in a normal window,
// as this flag is used in scrnsave.c to differentiate from full
// screen.
fChildPreview = TRUE;
// init size to half of (primary) screen by default
ncx = GetSystemMetrics( SM_CXSCREEN ) >> 1;
ncy = GetSystemMetrics( SM_CYSCREEN ) >> 1;
nx = 0;
ny = 0;
if( initParam ) {
// get size of window from args
LPCTSTR szArgs = (LPCTSTR) initParam;
//mf: not yet implemented
}
LoadString(hMainInstance, IDS_DESCRIPTION, szScreenSaverTitle,
sizeof(szScreenSaverTitle) / sizeof(TCHAR));
pszWindowTitle = szScreenSaverTitle; // MUST differ from preview
uStyle = WS_VISIBLE | WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN |
WS_CLIPSIBLINGS;
hCursor = LoadCursor( NULL, IDC_ARROW );
// Wrap RealScreenSaverProc
wndProc = NormalWindowScreenSaverProc;
}
break;
default:
break;
}
size.width = ncx;
size.height = ncy;
pos.x = nx;
pos.y = ny;
// Create SSW window wrapper
pssw = new SSW( NULL, // parent
&size,
&pos,
FALSE, // bMotion
NULL // ChildSizeFunc
);
if( !pssw )
return FALSE;
// Initialize the window class and create the window
#ifdef SS_INITIAL_CLEAR
hbrBgMain = NULL;
#else
hbrBgMain = hbrBg;
#endif
if( !RegisterMainClass
(
wndProc,
hbrBgMain,
hCursor
) ||
!pssw->CreateSSWindow
(
hMainInstance,
uStyle,
uExStyle,
pszWindowTitle,
wndProc,
pszWindowClass,
hwndParent // mf: ! hwndParentOverride
) )
{
delete pssw;
return FALSE;
}
if( type != SS_TYPE_PREVIEW )
#ifndef SS_DEBUG
SetForegroundWindow( pssw->hwnd );
#else
{
if( !SetForegroundWindow( pssw->hwnd ) )
SS_DBGPRINT( "Main_Proc: SetForegroundWindow failed\n" );
}
#endif
// Always configure the main window for gdi
pssw->ConfigureForGdi();
psswMain = pssw;
return TRUE;
}
/**\
* CreateChildWindow
* Creates a child window of the parent window
* This is a kind of wrapper-constructor
\**/
PSSW
SCRNSAVE::CreateChildWindow( FLOATER_INFO *pFloater )
{
pFloater->bSubWindow = FALSE; // default is no logical subwin's
// Register child window class
// This only has to be done once, since so far, all child window
// classes are the same
if( !pFloater->bSubWindow && !RegisterChildClass() )
return NULL;
return CreateChildWindow( psswMain, pFloater );
}
PSSW
SCRNSAVE::CreateChildWindow( PSSW psswParent, FLOATER_INFO *pFloater )
{
UINT uStyle = 0;
UINT uExStyle = 0;
PSSW pssw;
uStyle = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
// Size and position are NULL here, as the SSW will call the size
// function callback in pFloater to get these and other values
// Create the SSW window wrapper
pssw = new SSW( psswParent, // parent
NULL, // size
NULL, // position
pFloater->bMotion,
pFloater->ChildSizeFunc
);
if( !pssw )
return NULL;
if( pFloater->bSubWindow )
// Don't need to create win32 window
return pssw;
// Create a window
if( !pssw->CreateSSWindow
(
hMainInstance,
uStyle,
0, // uExStyle
szScreenSaverTitle ,
SS_ScreenSaverProc,
pszChildWindowClass,
NULL // hwndParentOverride
) )
{
delete pssw;
return NULL;
}
return pssw;
}
/**\
* RegisterMainClass
* Registers class of the main SS window
\**/
static BOOL
RegisterMainClass( WNDPROC wndProc, HBRUSH hbrBg, HCURSOR hCursor )
{
WNDCLASS cls;
cls.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS | CS_OWNDC;
cls.lpfnWndProc = wndProc;
cls.cbClsExtra = 0;
cls.cbWndExtra = 0;
cls.hInstance = hMainInstance;
cls.hIcon = LoadIcon( hMainInstance, MAKEINTATOM( ID_APP ) );
cls.hCursor = hCursor;
cls.hbrBackground = hbrBg;
cls.lpszMenuName = (LPTSTR)NULL;
cls.lpszClassName = (LPTSTR)pszWindowClass;
return RegisterClass(&cls);
}
/**\
* RegisterChildClass
* Registers class of a standard child window
\**/
static BOOL
RegisterChildClass()
{
static BOOL bRegistered = FALSE;
if( bRegistered )
return TRUE;
WNDCLASS cls;
cls.style = CS_VREDRAW | CS_HREDRAW;
cls.lpfnWndProc = SS_ScreenSaverProc;
cls.cbClsExtra = 0;
cls.cbWndExtra = 0;
cls.hInstance = hMainInstance;
cls.hIcon = NULL;
cls.hCursor = NULL;
cls.hbrBackground = NULL;
cls.lpszMenuName = (LPTSTR)NULL;
cls.lpszClassName = pszChildWindowClass;
if( !RegisterClass(&cls) )
return FALSE;
// success
bRegistered = TRUE;
return TRUE;
}
/**Public*Routine**\
* AttemptResolutionSwitch
* Try doing resolution switching to match or get close to the desired size.
\**/
static BOOL
AttemptResolutionSwitch( int width, int height, ISIZE *pNewSize )
{
BOOL bChanged = FALSE;
// Try doing resolution switching to match or get close to the
// desired width and height
// Try switching to requested size
#if 0
//mf: not ready for prime time
if( ss_ChangeDisplaySettings( width, height, 0 ) ) {
#else
if( 0 ) {
// for now force failure of user request and try standard 640x480
#endif
bChanged = TRUE;
} else {
// Can't switch to requested size, try for best match
// mf: !!! for now, let's play it safe and just try 640x480.
width = 640;
height = 480;
// If screen already this size or less, leave be
if( (GetSystemMetrics( SM_CXSCREEN ) <= width) &&
(GetSystemMetrics( SM_CYSCREEN ) <= height) )
return FALSE;
//mf: use this when trying for best match
// ss_QueryDisplaySettings();
if( ss_ChangeDisplaySettings( width, height, 0 ) )
bChanged = TRUE;
}
if( bChanged ) {
pNewSize->width = width;
pNewSize->height = height;
}
return bChanged;
}
#ifdef SS_INITIAL_CLEAR
static void
InitialClear( PSSW *pssw )
{
ss_GdiRectWipeClear( pssw->hwnd, pssw->size.width, pssw->size.height );
}
#endif // SS_INITIAL_CLEAR
/**\
* CloseWindows
* Close down any open windows.
* This sends a WM_CLOSE message to the top-level window if it is still open. If
* the window has any children, they are also closed. For each window, the
* SSW destructor is called.
\**/
void
SCRNSAVE::CloseWindows()
{
if( psswMain ) {
if( psswMain->bOwnWindow )
DestroyWindow( psswMain->hwnd );
else
delete psswMain;
}
}
/**\
* SCRNSAVE destructor
\**/
SCRNSAVE::~SCRNSAVE()
{
// Close any open windows (there might be some open if errors occurred)
CloseWindows();
if( bResSwitch ) {
// Restore previous display settings
ChangeDisplaySettings(NULL, CDS_FULLSCREEN);
}
gpss = NULL;
}