diff --git a/Generals/Code/GameEngine/Source/Common/GameEngine.cpp b/Generals/Code/GameEngine/Source/Common/GameEngine.cpp index bca49f07cc..997bd4bf8b 100644 --- a/Generals/Code/GameEngine/Source/Common/GameEngine.cpp +++ b/Generals/Code/GameEngine/Source/Common/GameEngine.cpp @@ -299,6 +299,14 @@ void GameEngine::init( int argc, char *argv[] ) initSubsystem(TheArchiveFileSystem, "TheArchiveFileSystem", createArchiveFileSystem(), NULL); // this MUST come after TheLocalFileSystem creation initSubsystem(TheWritableGlobalData, "TheWritableGlobalData", MSGNEW("GameEngineSubsystem") GlobalData(), &xferCRC, "Data\\INI\\Default\\GameData.ini", "Data\\INI\\GameData.ini"); + + // TheSuperHackers @bugfix helmutbuhler 14/04/2025 + // Pump messages during startup to ensure that the application window is correctly + // positioned on slower computers and in debug builds by a later call to SetWindowPos. + // It is unclear what the issue with SetWindowPos is when it fails to reposition the window. + serviceWindowsOS(); + + #if defined(RTS_DEBUG) || defined(RTS_INTERNAL) // If we're in Debug or Internal, load the Debug info as well. ini.load( AsciiString( "Data\\INI\\GameDataDebug.ini" ), INI_LOAD_OVERWRITE, NULL ); diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 6c327fa4f4..684bf2e42d 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -41,6 +41,11 @@ //#define CREATE_DX8_FPU_PRESERVE #define WW3D_DEVTYPE D3DDEVTYPE_HAL +#if defined(_MSC_VER) && _MSC_VER < 1300 +#undef WINVER +#define WINVER 0x0500 // Required to access GetMonitorInfo in VC6. +#endif + #include "dx8wrapper.h" #include "dx8webbrowser.h" #include "dx8fvf.h" @@ -230,6 +235,27 @@ void Non_Fatal_Log_DX8_ErrorCode(unsigned res,const char * file,int line) } } +// TheSuperHackers @info helmutbuhler 14/04/2025 +// Helper function that moves x and y such that the inner rect fits into the outer rect. +// If the inner rect already is in the outer rect, then this does nothing. +// If the inner rect is larger than the outer rect, then the inner rect will be aligned to the top left of the outer rect. +void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) +{ + int dx = 0; + if (inner.right > outer.right) + dx = outer.right-inner.right; + if (inner.left < outer.left) + dx = outer.left-inner.left; + + int dy = 0; + if (inner.bottom > outer.bottom) + dy = outer.bottom-inner.bottom; + if (inner.top < outer.top) + dy = outer.top-inner.top; + + *x += dx; + *y += dy; +} bool DX8Wrapper::Init(void * hwnd, bool lite) @@ -797,6 +823,60 @@ void DX8Wrapper::Get_Format_Name(unsigned int format, StringClass *tex_format) } } +void DX8Wrapper::Resize_And_Position_Window() +{ + // Get the current dimensions of the 'render area' of the window + RECT rect = { 0 }; + ::GetClientRect (_Hwnd, &rect); + + // Is the window the correct size for this resolution? + if ((rect.right-rect.left) != ResolutionWidth || + (rect.bottom-rect.top) != ResolutionHeight) { + + // Calculate what the main window's bounding rectangle should be to + // accommodate this resolution + rect.left = 0; + rect.top = 0; + rect.right = ResolutionWidth; + rect.bottom = ResolutionHeight; + DWORD dwstyle = ::GetWindowLong (_Hwnd, GWL_STYLE); + AdjustWindowRect (&rect, dwstyle, FALSE); + int width = rect.right-rect.left; + int height = rect.bottom-rect.top; + + // Resize the window to fit this resolution + if (!IsWindowed) + { + ::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, width, height, SWP_NOSIZE | SWP_NOMOVE); + + DEBUG_LOG(("Window resized to w:%d h:%d\n", width, height)); + } + else + { + // TheSuperHackers @feature helmutbuhler 14/04/2025 + // Center the window in the workarea of the monitor it is on. + MONITORINFO mi = {sizeof(MONITORINFO)}; + GetMonitorInfo(MonitorFromWindow(_Hwnd, MONITOR_DEFAULTTOPRIMARY), &mi); + int left = (mi.rcWork.left + mi.rcWork.right - width) / 2; + int top = (mi.rcWork.top + mi.rcWork.bottom - height) / 2; + + // TheSuperHackers @feature helmutbuhler 14/04/2025 + // Move the window to try fit it into the monitor area, if one of its dimensions is larger than the work area. + // Otherwise align the window to the top left edges, if it is even larger than the monitor area. + RECT rectClient; + rectClient.left = left - rect.left; + rectClient.top = top - rect.top; + rectClient.right = rectClient.left + ResolutionWidth; + rectClient.bottom = rectClient.top + ResolutionHeight; + MoveRectIntoOtherRect(rectClient, mi.rcMonitor, &left, &top); + + ::SetWindowPos (_Hwnd, NULL, left, top, width, height, SWP_NOZORDER); + + DEBUG_LOG(("Window positioned to x:%d y:%d, resized to w:%d h:%d\n", left, top, width, height)); + } + } +} + bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int windowed, bool resize_window,bool reset_device, bool restore_assets) { @@ -838,36 +918,7 @@ bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int // push the client area to be the size you really want. // if ( resize_window && windowed ) { if (resize_window) { - - // Get the current dimensions of the 'render area' of the window - RECT rect = { 0 }; - ::GetClientRect (_Hwnd, &rect); - - // Is the window the correct size for this resolution? - if ((rect.right-rect.left) != ResolutionWidth || - (rect.bottom-rect.top) != ResolutionHeight) { - - // Calculate what the main window's bounding rectangle should be to - // accomodate this resolution - rect.left = 0; - rect.top = 0; - rect.right = ResolutionWidth; - rect.bottom = ResolutionHeight; - DWORD dwstyle = ::GetWindowLong (_Hwnd, GWL_STYLE); - AdjustWindowRect (&rect, dwstyle, FALSE); - - // Resize the window to fit this resolution - if (!windowed) - ::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, rect.right-rect.left, rect.bottom-rect.top,SWP_NOSIZE |SWP_NOMOVE); - else - ::SetWindowPos (_Hwnd, - NULL, - 0, - 0, - rect.right-rect.left, - rect.bottom-rect.top, - SWP_NOZORDER | SWP_NOMOVE); - } + Resize_And_Position_Window(); } #endif //must be either resetting existing device or creating a new one. @@ -1115,37 +1166,7 @@ bool DX8Wrapper::Set_Device_Resolution(int width,int height,int bits,int windowe } if (resize_window) { - - // Get the current dimensions of the 'render area' of the window - RECT rect = { 0 }; - ::GetClientRect (_Hwnd, &rect); - - // Is the window the correct size for this resolution? - if ((rect.right-rect.left) != ResolutionWidth || - (rect.bottom-rect.top) != ResolutionHeight) - { - - // Calculate what the main window's bounding rectangle should be to - // accomodate this resolution - rect.left = 0; - rect.top = 0; - rect.right = ResolutionWidth; - rect.bottom = ResolutionHeight; - DWORD dwstyle = ::GetWindowLong (_Hwnd, GWL_STYLE); - AdjustWindowRect (&rect, dwstyle, FALSE); - - // Resize the window to fit this resolution - if (!windowed) - ::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, rect.right-rect.left, rect.bottom-rect.top,SWP_NOSIZE |SWP_NOMOVE); - else - ::SetWindowPos (_Hwnd, - NULL, - 0, - 0, - rect.right-rect.left, - rect.bottom-rect.top, - SWP_NOZORDER | SWP_NOMOVE); - } + Resize_And_Position_Window(); } #pragma message("TODO: support changing windowed status and changing the bit depth") return Reset_Device(); diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h index b8bd2ddeac..dae6c6d1a7 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h @@ -555,6 +555,7 @@ class DX8Wrapper /* ** Internal functions */ + static void Resize_And_Position_Window(); static bool Find_Color_And_Z_Mode(int resx,int resy,int bitdepth,D3DFORMAT * set_colorbuffer,D3DFORMAT * set_backbuffer, D3DFORMAT * set_zmode); static bool Find_Color_Mode(D3DFORMAT colorbuffer, int resx, int resy, UINT *mode); static bool Find_Z_Mode(D3DFORMAT colorbuffer,D3DFORMAT backbuffer, D3DFORMAT *zmode); diff --git a/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp b/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp index 9e79d39979..c8a69cd368 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp @@ -371,6 +371,12 @@ void GameEngine::init( int argc, char *argv[] ) #endif///////////////////////////////////////////////////////////////////////////////////////////// + // TheSuperHackers @bugfix helmutbuhler 14/04/2025 + // Pump messages during startup to ensure that the application window is correctly + // positioned on slower computers and in debug builds by a later call to SetWindowPos. + // It is unclear what the issue with SetWindowPos is when it fails to reposition the window. + serviceWindowsOS(); + #if defined(RTS_DEBUG) || defined(RTS_INTERNAL) // If we're in Debug or Internal, load the Debug info as well. diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 477d4d2c07..d67fc9ef32 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -45,6 +45,11 @@ //#define CREATE_DX8_FPU_PRESERVE #define WW3D_DEVTYPE D3DDEVTYPE_HAL +#if defined(_MSC_VER) && _MSC_VER < 1300 +#undef WINVER +#define WINVER 0x0500 // Required to access GetMonitorInfo in VC6. +#endif + #include "dx8wrapper.h" #include "dx8webbrowser.h" #include "dx8fvf.h" @@ -242,6 +247,27 @@ void Non_Fatal_Log_DX8_ErrorCode(unsigned res,const char * file,int line) } } +// TheSuperHackers @info helmutbuhler 14/04/2025 +// Helper function that moves x and y such that the inner rect fits into the outer rect. +// If the inner rect already is in the outer rect, then this does nothing. +// If the inner rect is larger than the outer rect, then the inner rect will be aligned to the top left of the outer rect. +void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) +{ + int dx = 0; + if (inner.right > outer.right) + dx = outer.right-inner.right; + if (inner.left < outer.left) + dx = outer.left-inner.left; + + int dy = 0; + if (inner.bottom > outer.bottom) + dy = outer.bottom-inner.bottom; + if (inner.top < outer.top) + dy = outer.top-inner.top; + + *x += dx; + *y += dy; +} bool DX8Wrapper::Init(void * hwnd, bool lite) @@ -886,6 +912,60 @@ void DX8Wrapper::Get_Format_Name(unsigned int format, StringClass *tex_format) } } +void DX8Wrapper::Resize_And_Position_Window() +{ + // Get the current dimensions of the 'render area' of the window + RECT rect = { 0 }; + ::GetClientRect (_Hwnd, &rect); + + // Is the window the correct size for this resolution? + if ((rect.right-rect.left) != ResolutionWidth || + (rect.bottom-rect.top) != ResolutionHeight) { + + // Calculate what the main window's bounding rectangle should be to + // accommodate this resolution + rect.left = 0; + rect.top = 0; + rect.right = ResolutionWidth; + rect.bottom = ResolutionHeight; + DWORD dwstyle = ::GetWindowLong (_Hwnd, GWL_STYLE); + AdjustWindowRect (&rect, dwstyle, FALSE); + int width = rect.right-rect.left; + int height = rect.bottom-rect.top; + + // Resize the window to fit this resolution + if (!IsWindowed) + { + ::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, width, height, SWP_NOSIZE | SWP_NOMOVE); + + DEBUG_LOG(("Window resized to w:%d h:%d\n", width, height)); + } + else + { + // TheSuperHackers @feature helmutbuhler 14/04/2025 + // Center the window in the workarea of the monitor it is on. + MONITORINFO mi = {sizeof(MONITORINFO)}; + GetMonitorInfo(MonitorFromWindow(_Hwnd, MONITOR_DEFAULTTOPRIMARY), &mi); + int left = (mi.rcWork.left + mi.rcWork.right - width) / 2; + int top = (mi.rcWork.top + mi.rcWork.bottom - height) / 2; + + // TheSuperHackers @feature helmutbuhler 14/04/2025 + // Move the window to try fit it into the monitor area, if one of its dimensions is larger than the work area. + // Otherwise align the window to the top left edges, if it is even larger than the monitor area. + RECT rectClient; + rectClient.left = left - rect.left; + rectClient.top = top - rect.top; + rectClient.right = rectClient.left + ResolutionWidth; + rectClient.bottom = rectClient.top + ResolutionHeight; + MoveRectIntoOtherRect(rectClient, mi.rcMonitor, &left, &top); + + ::SetWindowPos (_Hwnd, NULL, left, top, width, height, SWP_NOZORDER); + + DEBUG_LOG(("Window positioned to x:%d y:%d, resized to w:%d h:%d\n", left, top, width, height)); + } + } +} + bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int windowed, bool resize_window,bool reset_device, bool restore_assets) { @@ -927,36 +1007,7 @@ bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int // push the client area to be the size you really want. // if ( resize_window && windowed ) { if (resize_window) { - - // Get the current dimensions of the 'render area' of the window - RECT rect = { 0 }; - ::GetClientRect (_Hwnd, &rect); - - // Is the window the correct size for this resolution? - if ((rect.right-rect.left) != ResolutionWidth || - (rect.bottom-rect.top) != ResolutionHeight) { - - // Calculate what the main window's bounding rectangle should be to - // accomodate this resolution - rect.left = 0; - rect.top = 0; - rect.right = ResolutionWidth; - rect.bottom = ResolutionHeight; - DWORD dwstyle = ::GetWindowLong (_Hwnd, GWL_STYLE); - AdjustWindowRect (&rect, dwstyle, FALSE); - - // Resize the window to fit this resolution - if (!windowed) - ::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, rect.right-rect.left, rect.bottom-rect.top,SWP_NOSIZE |SWP_NOMOVE); - else - ::SetWindowPos (_Hwnd, - NULL, - 0, - 0, - rect.right-rect.left, - rect.bottom-rect.top, - SWP_NOZORDER | SWP_NOMOVE); - } + Resize_And_Position_Window(); } #endif //must be either resetting existing device or creating a new one. @@ -1205,37 +1256,7 @@ bool DX8Wrapper::Set_Device_Resolution(int width,int height,int bits,int windowe } if (resize_window) { - - // Get the current dimensions of the 'render area' of the window - RECT rect = { 0 }; - ::GetClientRect (_Hwnd, &rect); - - // Is the window the correct size for this resolution? - if ((rect.right-rect.left) != ResolutionWidth || - (rect.bottom-rect.top) != ResolutionHeight) - { - - // Calculate what the main window's bounding rectangle should be to - // accomodate this resolution - rect.left = 0; - rect.top = 0; - rect.right = ResolutionWidth; - rect.bottom = ResolutionHeight; - DWORD dwstyle = ::GetWindowLong (_Hwnd, GWL_STYLE); - AdjustWindowRect (&rect, dwstyle, FALSE); - - // Resize the window to fit this resolution - if (!windowed) - ::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, rect.right-rect.left, rect.bottom-rect.top,SWP_NOSIZE |SWP_NOMOVE); - else - ::SetWindowPos (_Hwnd, - NULL, - 0, - 0, - rect.right-rect.left, - rect.bottom-rect.top, - SWP_NOZORDER | SWP_NOMOVE); - } + Resize_And_Position_Window(); } #pragma message("TODO: support changing windowed status and changing the bit depth") return Reset_Device(); diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h index 4f0fead4ec..b87250b78e 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h @@ -612,6 +612,7 @@ class DX8Wrapper /* ** Internal functions */ + static void Resize_And_Position_Window(); static bool Find_Color_And_Z_Mode(int resx,int resy,int bitdepth,D3DFORMAT * set_colorbuffer,D3DFORMAT * set_backbuffer, D3DFORMAT * set_zmode); static bool Find_Color_Mode(D3DFORMAT colorbuffer, int resx, int resy, UINT *mode); static bool Find_Z_Mode(D3DFORMAT colorbuffer,D3DFORMAT backbuffer, D3DFORMAT *zmode);