From dea5cf9ba45db6b28581b2dadf1c92c62fb0ff75 Mon Sep 17 00:00:00 2001
From: Randy Heit <rheit@zdoom.fake>
Date: Tue, 13 Feb 2007 00:10:16 +0000
Subject: [PATCH] - Added two new cvars (win_x and win_y) that keep track of
 the window   position when not playing in fullscreen mode. - Changed the
 upper-left window positioning that was always used in debug   builds into a
 command line option (-0), so debug and release builds behave   the same.

SVN r482 (trunk)
---
 docs/rh-log.txt        |   7 +++
 src/win32/fb_d3d9.cpp  |   8 +--
 src/win32/fb_ddraw.cpp |   6 ++-
 src/win32/hardware.cpp | 108 +++++++++++++++++++++++++++++++++++++++++
 src/win32/hardware.h   |   3 ++
 src/win32/i_main.cpp   |  10 ++--
 src/win32/i_movie.cpp  |  11 +++--
 7 files changed, 139 insertions(+), 14 deletions(-)

diff --git a/docs/rh-log.txt b/docs/rh-log.txt
index 4afc362be..78040ef17 100644
--- a/docs/rh-log.txt
+++ b/docs/rh-log.txt
@@ -1,3 +1,10 @@
+February 12, 2007
+- Added two new cvars (win_x and win_y) that keep track of the window
+  position when not playing in fullscreen mode.
+- Changed the upper-left window positioning that was always used in debug
+  builds into a command line option (-0), so debug and release builds behave
+  the same.
+
 February 10, 2007 (Changes by Graf Zahl)
 - Changed earthquake code to not add all the intensities but use the maximum
   in DEarthQuake::StaticGetQuakeIntensity. The reason for this: Quakes were
diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp
index a49a36f7e..2ef976c50 100644
--- a/src/win32/fb_d3d9.cpp
+++ b/src/win32/fb_d3d9.cpp
@@ -3,7 +3,7 @@
 ** Code to let ZDoom use Direct3D 9 as a simple framebuffer
 **
 **---------------------------------------------------------------------------
-** Copyright 1998-2006 Randy Heit
+** Copyright 1998-2007 Randy Heit
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without
@@ -280,7 +280,7 @@ bool D3DFB::CreateResources ()
 	if (!Windowed)
 	{
 		// Remove the window border in fullscreen mode
-		SetWindowLongPtr (Window, GWL_STYLE, WS_POPUP|WS_VISIBLE);
+		SetWindowLong (Window, GWL_STYLE, WS_POPUP|WS_VISIBLE|WS_SYSMENU);
 	}
 	else
 	{
@@ -291,7 +291,7 @@ bool D3DFB::CreateResources ()
 		LOG2 ("Resize window to %dx%d\n", sizew, sizeh);
 		VidResizing = true;
 		// Make sure the window has a border in windowed mode
-		SetWindowLongPtr (Window, GWL_STYLE, WS_VISIBLE|WS_OVERLAPPEDWINDOW);
+		SetWindowLong (Window, GWL_STYLE, WS_VISIBLE|WS_OVERLAPPEDWINDOW);
 		if (GetWindowLong (Window, GWL_EXSTYLE) & WS_EX_TOPMOST)
 		{
 			// Direct3D 9 will apparently add WS_EX_TOPMOST to fullscreen windows,
@@ -306,6 +306,7 @@ bool D3DFB::CreateResources ()
 			SetWindowPos (Window, NULL, 0, 0, sizew, sizeh,
 				SWP_DRAWFRAME | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOZORDER);
 		}
+		I_RestoreWindowedPos ();
 		VidResizing = false;
 	}
 	if (FAILED(D3DDevice->CreatePixelShader (PalTexShaderDef, &PalTexShader)))
@@ -326,6 +327,7 @@ bool D3DFB::CreateResources ()
 
 void D3DFB::ReleaseResources ()
 {
+	I_SaveWindowedPos ();
 	if (FBTexture != NULL)
 	{
 		FBTexture->Release();
diff --git a/src/win32/fb_ddraw.cpp b/src/win32/fb_ddraw.cpp
index ea4c4e726..7a05ccf82 100644
--- a/src/win32/fb_ddraw.cpp
+++ b/src/win32/fb_ddraw.cpp
@@ -219,6 +219,7 @@ DDrawFB::DDrawFB (int width, int height, bool fullscreen)
 
 DDrawFB::~DDrawFB ()
 {
+	I_SaveWindowedPos ();
 	ReleaseResources ();
 }
 
@@ -233,7 +234,7 @@ bool DDrawFB::CreateResources ()
 	if (!Windowed)
 	{
 		// Remove the window border in fullscreen mode
-		SetWindowLongPtr (Window, GWL_STYLE, WS_POPUP|WS_VISIBLE);
+		SetWindowLong (Window, GWL_STYLE, WS_POPUP|WS_VISIBLE|WS_SYSMENU);
 
 		TrueHeight = Height;
 		for (Win32Video::ModeInfo *mode = static_cast<Win32Video *>(Video)->m_Modes; mode != NULL; mode = mode->next)
@@ -307,12 +308,13 @@ bool DDrawFB::CreateResources ()
 		LOG2 ("Resize window to %dx%d\n", sizew, sizeh);
 		VidResizing = true;
 		// Make sure the window has a border in windowed mode
-		SetWindowLongPtr (Window, GWL_STYLE, WS_VISIBLE|WS_OVERLAPPEDWINDOW);
+		SetWindowLong (Window, GWL_STYLE, WS_VISIBLE|WS_OVERLAPPEDWINDOW);
 		if (!SetWindowPos (Window, NULL, 0, 0, sizew, sizeh,
 			SWP_DRAWFRAME | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOZORDER))
 		{
 			LOG1 ("SetWindowPos failed because %08lx\n", GetLastError());
 		}
+		I_RestoreWindowedPos ();
 		VidResizing = false;
 
 		// Create the clipper
diff --git a/src/win32/hardware.cpp b/src/win32/hardware.cpp
index b0debeb69..20febd73a 100644
--- a/src/win32/hardware.cpp
+++ b/src/win32/hardware.cpp
@@ -49,6 +49,11 @@ EXTERN_CVAR (Bool, ticker)
 EXTERN_CVAR (Bool, fullscreen)
 EXTERN_CVAR (Float, vid_winscale)
 
+CVAR(Int, win_x, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
+CVAR(Int, win_y, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
+
+extern HWND Window;
+
 bool ForceWindowed;
 
 IVideo *Video;
@@ -163,6 +168,109 @@ void I_ClosestResolution (int *width, int *height, int bits)
 	}
 }	
 
+static void GetCenteredPos (int &winx, int &winy, int &winw, int &winh, int &scrwidth, int &scrheight)
+{
+	DEVMODE displaysettings;
+	RECT rect;
+	int cx, cy;
+
+	memset (&displaysettings, 0, sizeof(displaysettings));
+	displaysettings.dmSize = sizeof(displaysettings);
+	EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &displaysettings);
+	scrwidth = (int)displaysettings.dmPelsWidth;
+	scrheight = (int)displaysettings.dmPelsHeight;
+	GetWindowRect (Window, &rect);
+	cx = scrwidth / 2;
+	cy = scrheight / 2;
+	winx = cx - (winw = rect.right - rect.left) / 2;
+	winy = cy - (winh = rect.bottom - rect.top) / 2;
+}
+
+static void KeepWindowOnScreen (int &winx, int &winy, int winw, int winh, int scrwidth, int scrheight)
+{
+	// If the window is too large to fit entirely on the screen, at least
+	// keep its upperleft corner visible.
+	if (winx + winw > scrwidth)
+	{
+		winx = scrwidth - winw;
+	}
+	if (winx < 0)
+	{
+		winx = 0;
+	}
+	if (winy + winh > scrheight)
+	{
+		winy = scrheight - winh;
+	}
+	if (winy < 0)
+	{
+		winy = 0;
+	}
+}
+
+void I_SaveWindowedPos ()
+{
+	// Don't save if we were run with the -0 option.
+	if (Args.CheckParm ("-0"))
+	{
+		return;
+	}
+	// Make sure we only save the window position if it's not fullscreen.
+	if ((GetWindowLong (Window, GWL_STYLE) & WS_OVERLAPPEDWINDOW) == WS_OVERLAPPEDWINDOW)
+	{
+		RECT wrect;
+
+		if (GetWindowRect (Window, &wrect))
+		{
+			// If (win_x,win_y) specify to center the window, don't change them
+			// if the window is still centered.
+			if (win_x < 0 || win_y < 0)
+			{
+				int winx, winy, winw, winh, scrwidth, scrheight;
+
+				GetCenteredPos (winx, winy, winw, winh, scrwidth, scrheight);
+				KeepWindowOnScreen (winx, winy, winw, winh, scrwidth, scrheight);
+				if (win_x < 0 && winx == wrect.left)
+				{
+					wrect.left = win_x;
+				}
+				if (win_y < 0 && winy == wrect.top)
+				{
+					wrect.top = win_y;
+				}
+			}
+			win_x = wrect.left;
+			win_y = wrect.top;
+		}
+	}
+}
+
+void I_RestoreWindowedPos ()
+{
+	int winx, winy, winw, winh, scrwidth, scrheight;
+
+	GetCenteredPos (winx, winy, winw, winh, scrwidth, scrheight);
+
+	// Just move to (0,0) if we were run with the -0 option.
+	if (Args.CheckParm ("-0"))
+	{
+		winx = winy = 0;
+	}
+	else
+	{
+		if (win_x >= 0)
+		{
+			winx = win_x;
+		}
+		if (win_y >= 0)
+		{
+			winy = win_y;
+		}
+		KeepWindowOnScreen (winx, winy, winw, winh, scrwidth, scrheight);
+	}
+	MoveWindow (Window, winx, winy, winw, winh, TRUE);
+}
+
 extern int NewWidth, NewHeight, NewBits, DisplayBits;
 
 CUSTOM_CVAR (Bool, fullscreen, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
diff --git a/src/win32/hardware.h b/src/win32/hardware.h
index 39579be96..fd1e92d45 100644
--- a/src/win32/hardware.h
+++ b/src/win32/hardware.h
@@ -54,6 +54,9 @@ class IVideo
 void I_InitGraphics ();
 void I_ShutdownGraphics ();
 
+void I_SaveWindowedPos ();
+void I_RestoreWindowedPos ();
+
 extern IVideo *Video;
 
 #endif	// __HARDWARE_H__
diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp
index 011126083..27880f324 100644
--- a/src/win32/i_main.cpp
+++ b/src/win32/i_main.cpp
@@ -822,9 +822,11 @@ void DoMain (HINSTANCE hInstance)
 		EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &displaysettings);
 		x = (displaysettings.dmPelsWidth - width) / 2;
 		y = (displaysettings.dmPelsHeight - height) / 2;
-#if _DEBUG
-		x = y = 0;
-#endif
+
+		if (Args.CheckParm ("-0"))
+		{
+			x = y = 0;
+		}
 
 		TheInvisibleCursor = LoadCursor (hInstance, MAKEINTRESOURCE(IDC_INVISIBLECURSOR));
 		TheArrowCursor = LoadCursor (NULL, IDC_ARROW);
@@ -1100,7 +1102,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n
 	{
 		// Technically, it isn't really Internet Explorer that is needed, but this
 		// is an example of a specific program that will provide riched20.dll.
-		// But considering how extra stuff needs to be installed to make Windows 95
+		// But considering how much extra stuff needs to be installed to make Windows 95
 		// useable with pretty much any recent software, the chances are high that
 		// the user already has riched20.dll installed.
 		I_FatalError ("Sorry, you need to install Internet Explorer 3 or higher to play ZDoom on Windows 95.");
diff --git a/src/win32/i_movie.cpp b/src/win32/i_movie.cpp
index dbd2909da..05045bbdd 100644
--- a/src/win32/i_movie.cpp
+++ b/src/win32/i_movie.cpp
@@ -218,6 +218,7 @@ LRESULT CALLBACK MovieWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lP
 
 int I_PlayMovie (const char *name)
 {
+	HRESULT hr;
 	int returnval = MOVIE_Failed;
 	size_t namelen = strlen (name) + 1;
 	wchar_t *uniname = new wchar_t[namelen];
@@ -241,7 +242,7 @@ int I_PlayMovie (const char *name)
 			uniname[i] = L'\\';
 	}
 
-	if (FAILED(CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
+	if (FAILED(hr = CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
 		IID_IGraphBuilder, (void **)&graph)))
 	{
 		goto bomb1;
@@ -253,7 +254,7 @@ int I_PlayMovie (const char *name)
 	audio = NULL;
 	video = NULL;
 
-	if (FAILED(graph->RenderFile (uniname, NULL)))
+	if (FAILED(hr = graph->RenderFile (uniname, NULL)))
 	{
 		goto bomb2;
 	}
@@ -295,7 +296,7 @@ int I_PlayMovie (const char *name)
 			static_cast<Win32Video *> (Video)->BlankForGDI ();
 			static_cast<Win32Video *> (Video)->GoFullscreen (false);
 			static_cast<BaseWinFB *> (screen)->ReleaseResources ();
-			if (FAILED (drainhr) || FAILED(vidwin->put_FullScreenMode (OATRUE)))
+			if (FAILED (drainhr) || FAILED(hr = vidwin->put_FullScreenMode (OATRUE)))
 			{
 				SizeWindowForVideo ();
 				FullVideo = false;
@@ -314,7 +315,7 @@ int I_PlayMovie (const char *name)
 		}
 	}
 
-	if (FAILED (event->SetNotifyWindow ((OAHWND)Window, WM_GRAPHNOTIFY, 0)))
+	if (FAILED (hr = event->SetNotifyWindow ((OAHWND)Window, WM_GRAPHNOTIFY, 0)))
 	{
 		goto bomb3;
 	}
@@ -324,7 +325,7 @@ int I_PlayMovie (const char *name)
 	I_CheckNativeMouse (true);
 	SetWindowLongPtr (Window, GWLP_WNDPROC, (LONG_PTR)MovieWndProc);
 
-	if (FAILED (control->Run ()))
+	if (FAILED (hr = control->Run ()))
 	{
 		goto bomb4;
 	}