Skip to content

Commit d44d901

Browse files
authored
[GEN][ZH] Center Game App Window on startup and resolution change (#541)
1 parent e65006e commit d44d901

File tree

6 files changed

+180
-122
lines changed

6 files changed

+180
-122
lines changed

Generals/Code/GameEngine/Source/Common/GameEngine.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,14 @@ void GameEngine::init( int argc, char *argv[] )
299299
initSubsystem(TheArchiveFileSystem, "TheArchiveFileSystem", createArchiveFileSystem(), NULL); // this MUST come after TheLocalFileSystem creation
300300
initSubsystem(TheWritableGlobalData, "TheWritableGlobalData", MSGNEW("GameEngineSubsystem") GlobalData(), &xferCRC, "Data\\INI\\Default\\GameData.ini", "Data\\INI\\GameData.ini");
301301

302+
303+
// TheSuperHackers @bugfix helmutbuhler 14/04/2025
304+
// Pump messages during startup to ensure that the application window is correctly
305+
// positioned on slower computers and in debug builds by a later call to SetWindowPos.
306+
// It is unclear what the issue with SetWindowPos is when it fails to reposition the window.
307+
serviceWindowsOS();
308+
309+
302310
#if defined(RTS_DEBUG) || defined(RTS_INTERNAL)
303311
// If we're in Debug or Internal, load the Debug info as well.
304312
ini.load( AsciiString( "Data\\INI\\GameDataDebug.ini" ), INI_LOAD_OVERWRITE, NULL );

Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp

Lines changed: 82 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@
4141
//#define CREATE_DX8_FPU_PRESERVE
4242
#define WW3D_DEVTYPE D3DDEVTYPE_HAL
4343

44+
#if defined(_MSC_VER) && _MSC_VER < 1300
45+
#undef WINVER
46+
#define WINVER 0x0500 // Required to access GetMonitorInfo in VC6.
47+
#endif
48+
4449
#include "dx8wrapper.h"
4550
#include "dx8webbrowser.h"
4651
#include "dx8fvf.h"
@@ -230,6 +235,27 @@ void Non_Fatal_Log_DX8_ErrorCode(unsigned res,const char * file,int line)
230235
}
231236
}
232237

238+
// TheSuperHackers @info helmutbuhler 14/04/2025
239+
// Helper function that moves x and y such that the inner rect fits into the outer rect.
240+
// If the inner rect already is in the outer rect, then this does nothing.
241+
// 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.
242+
void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y)
243+
{
244+
int dx = 0;
245+
if (inner.right > outer.right)
246+
dx = outer.right-inner.right;
247+
if (inner.left < outer.left)
248+
dx = outer.left-inner.left;
249+
250+
int dy = 0;
251+
if (inner.bottom > outer.bottom)
252+
dy = outer.bottom-inner.bottom;
253+
if (inner.top < outer.top)
254+
dy = outer.top-inner.top;
255+
256+
*x += dx;
257+
*y += dy;
258+
}
233259

234260

235261
bool DX8Wrapper::Init(void * hwnd, bool lite)
@@ -797,6 +823,60 @@ void DX8Wrapper::Get_Format_Name(unsigned int format, StringClass *tex_format)
797823
}
798824
}
799825

826+
void DX8Wrapper::Resize_And_Position_Window()
827+
{
828+
// Get the current dimensions of the 'render area' of the window
829+
RECT rect = { 0 };
830+
::GetClientRect (_Hwnd, &rect);
831+
832+
// Is the window the correct size for this resolution?
833+
if ((rect.right-rect.left) != ResolutionWidth ||
834+
(rect.bottom-rect.top) != ResolutionHeight) {
835+
836+
// Calculate what the main window's bounding rectangle should be to
837+
// accommodate this resolution
838+
rect.left = 0;
839+
rect.top = 0;
840+
rect.right = ResolutionWidth;
841+
rect.bottom = ResolutionHeight;
842+
DWORD dwstyle = ::GetWindowLong (_Hwnd, GWL_STYLE);
843+
AdjustWindowRect (&rect, dwstyle, FALSE);
844+
int width = rect.right-rect.left;
845+
int height = rect.bottom-rect.top;
846+
847+
// Resize the window to fit this resolution
848+
if (!IsWindowed)
849+
{
850+
::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, width, height, SWP_NOSIZE | SWP_NOMOVE);
851+
852+
DEBUG_LOG(("Window resized to w:%d h:%d\n", width, height));
853+
}
854+
else
855+
{
856+
// TheSuperHackers @feature helmutbuhler 14/04/2025
857+
// Center the window in the workarea of the monitor it is on.
858+
MONITORINFO mi = {sizeof(MONITORINFO)};
859+
GetMonitorInfo(MonitorFromWindow(_Hwnd, MONITOR_DEFAULTTOPRIMARY), &mi);
860+
int left = (mi.rcWork.left + mi.rcWork.right - width) / 2;
861+
int top = (mi.rcWork.top + mi.rcWork.bottom - height) / 2;
862+
863+
// TheSuperHackers @feature helmutbuhler 14/04/2025
864+
// Move the window to try fit it into the monitor area, if one of its dimensions is larger than the work area.
865+
// Otherwise align the window to the top left edges, if it is even larger than the monitor area.
866+
RECT rectClient;
867+
rectClient.left = left - rect.left;
868+
rectClient.top = top - rect.top;
869+
rectClient.right = rectClient.left + ResolutionWidth;
870+
rectClient.bottom = rectClient.top + ResolutionHeight;
871+
MoveRectIntoOtherRect(rectClient, mi.rcMonitor, &left, &top);
872+
873+
::SetWindowPos (_Hwnd, NULL, left, top, width, height, SWP_NOZORDER);
874+
875+
DEBUG_LOG(("Window positioned to x:%d y:%d, resized to w:%d h:%d\n", left, top, width, height));
876+
}
877+
}
878+
}
879+
800880
bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int windowed,
801881
bool resize_window,bool reset_device, bool restore_assets)
802882
{
@@ -838,36 +918,7 @@ bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int
838918
// push the client area to be the size you really want.
839919
// if ( resize_window && windowed ) {
840920
if (resize_window) {
841-
842-
// Get the current dimensions of the 'render area' of the window
843-
RECT rect = { 0 };
844-
::GetClientRect (_Hwnd, &rect);
845-
846-
// Is the window the correct size for this resolution?
847-
if ((rect.right-rect.left) != ResolutionWidth ||
848-
(rect.bottom-rect.top) != ResolutionHeight) {
849-
850-
// Calculate what the main window's bounding rectangle should be to
851-
// accomodate this resolution
852-
rect.left = 0;
853-
rect.top = 0;
854-
rect.right = ResolutionWidth;
855-
rect.bottom = ResolutionHeight;
856-
DWORD dwstyle = ::GetWindowLong (_Hwnd, GWL_STYLE);
857-
AdjustWindowRect (&rect, dwstyle, FALSE);
858-
859-
// Resize the window to fit this resolution
860-
if (!windowed)
861-
::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, rect.right-rect.left, rect.bottom-rect.top,SWP_NOSIZE |SWP_NOMOVE);
862-
else
863-
::SetWindowPos (_Hwnd,
864-
NULL,
865-
0,
866-
0,
867-
rect.right-rect.left,
868-
rect.bottom-rect.top,
869-
SWP_NOZORDER | SWP_NOMOVE);
870-
}
921+
Resize_And_Position_Window();
871922
}
872923
#endif
873924
//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
11151166
}
11161167
if (resize_window)
11171168
{
1118-
1119-
// Get the current dimensions of the 'render area' of the window
1120-
RECT rect = { 0 };
1121-
::GetClientRect (_Hwnd, &rect);
1122-
1123-
// Is the window the correct size for this resolution?
1124-
if ((rect.right-rect.left) != ResolutionWidth ||
1125-
(rect.bottom-rect.top) != ResolutionHeight)
1126-
{
1127-
1128-
// Calculate what the main window's bounding rectangle should be to
1129-
// accomodate this resolution
1130-
rect.left = 0;
1131-
rect.top = 0;
1132-
rect.right = ResolutionWidth;
1133-
rect.bottom = ResolutionHeight;
1134-
DWORD dwstyle = ::GetWindowLong (_Hwnd, GWL_STYLE);
1135-
AdjustWindowRect (&rect, dwstyle, FALSE);
1136-
1137-
// Resize the window to fit this resolution
1138-
if (!windowed)
1139-
::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, rect.right-rect.left, rect.bottom-rect.top,SWP_NOSIZE |SWP_NOMOVE);
1140-
else
1141-
::SetWindowPos (_Hwnd,
1142-
NULL,
1143-
0,
1144-
0,
1145-
rect.right-rect.left,
1146-
rect.bottom-rect.top,
1147-
SWP_NOZORDER | SWP_NOMOVE);
1148-
}
1169+
Resize_And_Position_Window();
11491170
}
11501171
#pragma message("TODO: support changing windowed status and changing the bit depth")
11511172
return Reset_Device();

Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,7 @@ class DX8Wrapper
555555
/*
556556
** Internal functions
557557
*/
558+
static void Resize_And_Position_Window();
558559
static bool Find_Color_And_Z_Mode(int resx,int resy,int bitdepth,D3DFORMAT * set_colorbuffer,D3DFORMAT * set_backbuffer, D3DFORMAT * set_zmode);
559560
static bool Find_Color_Mode(D3DFORMAT colorbuffer, int resx, int resy, UINT *mode);
560561
static bool Find_Z_Mode(D3DFORMAT colorbuffer,D3DFORMAT backbuffer, D3DFORMAT *zmode);

GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,12 @@ void GameEngine::init( int argc, char *argv[] )
371371
#endif/////////////////////////////////////////////////////////////////////////////////////////////
372372

373373

374+
// TheSuperHackers @bugfix helmutbuhler 14/04/2025
375+
// Pump messages during startup to ensure that the application window is correctly
376+
// positioned on slower computers and in debug builds by a later call to SetWindowPos.
377+
// It is unclear what the issue with SetWindowPos is when it fails to reposition the window.
378+
serviceWindowsOS();
379+
374380

375381
#if defined(RTS_DEBUG) || defined(RTS_INTERNAL)
376382
// If we're in Debug or Internal, load the Debug info as well.

GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp

Lines changed: 82 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@
4545
//#define CREATE_DX8_FPU_PRESERVE
4646
#define WW3D_DEVTYPE D3DDEVTYPE_HAL
4747

48+
#if defined(_MSC_VER) && _MSC_VER < 1300
49+
#undef WINVER
50+
#define WINVER 0x0500 // Required to access GetMonitorInfo in VC6.
51+
#endif
52+
4853
#include "dx8wrapper.h"
4954
#include "dx8webbrowser.h"
5055
#include "dx8fvf.h"
@@ -242,6 +247,27 @@ void Non_Fatal_Log_DX8_ErrorCode(unsigned res,const char * file,int line)
242247
}
243248
}
244249

250+
// TheSuperHackers @info helmutbuhler 14/04/2025
251+
// Helper function that moves x and y such that the inner rect fits into the outer rect.
252+
// If the inner rect already is in the outer rect, then this does nothing.
253+
// 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.
254+
void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y)
255+
{
256+
int dx = 0;
257+
if (inner.right > outer.right)
258+
dx = outer.right-inner.right;
259+
if (inner.left < outer.left)
260+
dx = outer.left-inner.left;
261+
262+
int dy = 0;
263+
if (inner.bottom > outer.bottom)
264+
dy = outer.bottom-inner.bottom;
265+
if (inner.top < outer.top)
266+
dy = outer.top-inner.top;
267+
268+
*x += dx;
269+
*y += dy;
270+
}
245271

246272

247273
bool DX8Wrapper::Init(void * hwnd, bool lite)
@@ -886,6 +912,60 @@ void DX8Wrapper::Get_Format_Name(unsigned int format, StringClass *tex_format)
886912
}
887913
}
888914

915+
void DX8Wrapper::Resize_And_Position_Window()
916+
{
917+
// Get the current dimensions of the 'render area' of the window
918+
RECT rect = { 0 };
919+
::GetClientRect (_Hwnd, &rect);
920+
921+
// Is the window the correct size for this resolution?
922+
if ((rect.right-rect.left) != ResolutionWidth ||
923+
(rect.bottom-rect.top) != ResolutionHeight) {
924+
925+
// Calculate what the main window's bounding rectangle should be to
926+
// accommodate this resolution
927+
rect.left = 0;
928+
rect.top = 0;
929+
rect.right = ResolutionWidth;
930+
rect.bottom = ResolutionHeight;
931+
DWORD dwstyle = ::GetWindowLong (_Hwnd, GWL_STYLE);
932+
AdjustWindowRect (&rect, dwstyle, FALSE);
933+
int width = rect.right-rect.left;
934+
int height = rect.bottom-rect.top;
935+
936+
// Resize the window to fit this resolution
937+
if (!IsWindowed)
938+
{
939+
::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, width, height, SWP_NOSIZE | SWP_NOMOVE);
940+
941+
DEBUG_LOG(("Window resized to w:%d h:%d\n", width, height));
942+
}
943+
else
944+
{
945+
// TheSuperHackers @feature helmutbuhler 14/04/2025
946+
// Center the window in the workarea of the monitor it is on.
947+
MONITORINFO mi = {sizeof(MONITORINFO)};
948+
GetMonitorInfo(MonitorFromWindow(_Hwnd, MONITOR_DEFAULTTOPRIMARY), &mi);
949+
int left = (mi.rcWork.left + mi.rcWork.right - width) / 2;
950+
int top = (mi.rcWork.top + mi.rcWork.bottom - height) / 2;
951+
952+
// TheSuperHackers @feature helmutbuhler 14/04/2025
953+
// Move the window to try fit it into the monitor area, if one of its dimensions is larger than the work area.
954+
// Otherwise align the window to the top left edges, if it is even larger than the monitor area.
955+
RECT rectClient;
956+
rectClient.left = left - rect.left;
957+
rectClient.top = top - rect.top;
958+
rectClient.right = rectClient.left + ResolutionWidth;
959+
rectClient.bottom = rectClient.top + ResolutionHeight;
960+
MoveRectIntoOtherRect(rectClient, mi.rcMonitor, &left, &top);
961+
962+
::SetWindowPos (_Hwnd, NULL, left, top, width, height, SWP_NOZORDER);
963+
964+
DEBUG_LOG(("Window positioned to x:%d y:%d, resized to w:%d h:%d\n", left, top, width, height));
965+
}
966+
}
967+
}
968+
889969
bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int windowed,
890970
bool resize_window,bool reset_device, bool restore_assets)
891971
{
@@ -927,36 +1007,7 @@ bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int
9271007
// push the client area to be the size you really want.
9281008
// if ( resize_window && windowed ) {
9291009
if (resize_window) {
930-
931-
// Get the current dimensions of the 'render area' of the window
932-
RECT rect = { 0 };
933-
::GetClientRect (_Hwnd, &rect);
934-
935-
// Is the window the correct size for this resolution?
936-
if ((rect.right-rect.left) != ResolutionWidth ||
937-
(rect.bottom-rect.top) != ResolutionHeight) {
938-
939-
// Calculate what the main window's bounding rectangle should be to
940-
// accomodate this resolution
941-
rect.left = 0;
942-
rect.top = 0;
943-
rect.right = ResolutionWidth;
944-
rect.bottom = ResolutionHeight;
945-
DWORD dwstyle = ::GetWindowLong (_Hwnd, GWL_STYLE);
946-
AdjustWindowRect (&rect, dwstyle, FALSE);
947-
948-
// Resize the window to fit this resolution
949-
if (!windowed)
950-
::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, rect.right-rect.left, rect.bottom-rect.top,SWP_NOSIZE |SWP_NOMOVE);
951-
else
952-
::SetWindowPos (_Hwnd,
953-
NULL,
954-
0,
955-
0,
956-
rect.right-rect.left,
957-
rect.bottom-rect.top,
958-
SWP_NOZORDER | SWP_NOMOVE);
959-
}
1010+
Resize_And_Position_Window();
9601011
}
9611012
#endif
9621013
//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
12051256
}
12061257
if (resize_window)
12071258
{
1208-
1209-
// Get the current dimensions of the 'render area' of the window
1210-
RECT rect = { 0 };
1211-
::GetClientRect (_Hwnd, &rect);
1212-
1213-
// Is the window the correct size for this resolution?
1214-
if ((rect.right-rect.left) != ResolutionWidth ||
1215-
(rect.bottom-rect.top) != ResolutionHeight)
1216-
{
1217-
1218-
// Calculate what the main window's bounding rectangle should be to
1219-
// accomodate this resolution
1220-
rect.left = 0;
1221-
rect.top = 0;
1222-
rect.right = ResolutionWidth;
1223-
rect.bottom = ResolutionHeight;
1224-
DWORD dwstyle = ::GetWindowLong (_Hwnd, GWL_STYLE);
1225-
AdjustWindowRect (&rect, dwstyle, FALSE);
1226-
1227-
// Resize the window to fit this resolution
1228-
if (!windowed)
1229-
::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, rect.right-rect.left, rect.bottom-rect.top,SWP_NOSIZE |SWP_NOMOVE);
1230-
else
1231-
::SetWindowPos (_Hwnd,
1232-
NULL,
1233-
0,
1234-
0,
1235-
rect.right-rect.left,
1236-
rect.bottom-rect.top,
1237-
SWP_NOZORDER | SWP_NOMOVE);
1238-
}
1259+
Resize_And_Position_Window();
12391260
}
12401261
#pragma message("TODO: support changing windowed status and changing the bit depth")
12411262
return Reset_Device();

GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,7 @@ class DX8Wrapper
612612
/*
613613
** Internal functions
614614
*/
615+
static void Resize_And_Position_Window();
615616
static bool Find_Color_And_Z_Mode(int resx,int resy,int bitdepth,D3DFORMAT * set_colorbuffer,D3DFORMAT * set_backbuffer, D3DFORMAT * set_zmode);
616617
static bool Find_Color_Mode(D3DFORMAT colorbuffer, int resx, int resy, UINT *mode);
617618
static bool Find_Z_Mode(D3DFORMAT colorbuffer,D3DFORMAT backbuffer, D3DFORMAT *zmode);

0 commit comments

Comments
 (0)