Save and restore main window placement

Windows' default behavior is apparently to fill the display with the
app window, capped at 1920x1200.  This is annoyingly large for most
situations.

We now save the main window rect (LTRB) and maximization status in
the configuration area of the registry.  The window placement calls
are supposed to do something reasonable when the window would be
completely off-screen (e.g. because a secondary monitor was disabled).
This commit is contained in:
Andy McFadden 2021-05-10 14:04:50 -07:00
parent eff69cce86
commit 4235b47748
3 changed files with 105 additions and 9 deletions

View File

@ -133,6 +133,7 @@ static const UINT gFindReplaceID = RegisterWindowMessage(FINDMSGSTRING);
BEGIN_MESSAGE_MAP(MainWindow, CFrameWnd)
ON_WM_CREATE()
ON_WM_CLOSE()
ON_MESSAGE(WMU_LATE_INIT, OnLateInit)
//ON_MESSAGE(WMU_CLOSE_MAIN_DIALOG, OnCloseMainDialog)
ON_WM_SIZE()
@ -306,6 +307,12 @@ MainWindow::~MainWindow()
LOGI("MainWindow destructor complete");
}
void MainWindow::OnClose()
{
SaveWinPlacement();
CFrameWnd::OnClose();
}
BOOL MainWindow::PreCreateWindow(CREATESTRUCT& cs)
{
BOOL res = CFrameWnd::PreCreateWindow(cs);
@ -563,6 +570,8 @@ int MainWindow::OnCreate(LPCREATESTRUCT lpcs)
fStatusBar.SetPaneText(kProgressPane, L"");
RestoreWinPlacement();
return 0;
}
@ -1889,6 +1898,82 @@ void MainWindow::EventPause(int duration)
* ===================================
*/
static const WCHAR kMainWinSection[] = L"mainwin";
static const WCHAR kMainWin_Left[] = L"left";
static const WCHAR kMainWin_Top[] = L"top";
static const WCHAR kMainWin_Right[] = L"right";
static const WCHAR kMainWin_Bottom[] = L"bottom";
static const WCHAR kMainWin_Cmd[] = L"cmd";
void MainWindow::SaveWinPlacement()
{
// Capture the current window position. At the point where the destructor
// fires, too much has been shut down, so we need to do it here.
WINDOWPLACEMENT wndpl;
wndpl.length = sizeof(wndpl);
if (!GetWindowPlacement(&wndpl)) {
LOGW("Unable to get window placement");
return;
}
LOGD("Window is at ltrb=%ld,%ld %ldx%ld showCmd=%d",
wndpl.rcNormalPosition.left,
wndpl.rcNormalPosition.top,
wndpl.rcNormalPosition.right - wndpl.rcNormalPosition.left,
wndpl.rcNormalPosition.bottom - wndpl.rcNormalPosition.top,
wndpl.showCmd);
gMyApp.WriteProfileInt(kMainWinSection,
kMainWin_Left, wndpl.rcNormalPosition.left);
gMyApp.WriteProfileInt(kMainWinSection,
kMainWin_Top, wndpl.rcNormalPosition.top);
gMyApp.WriteProfileInt(kMainWinSection,
kMainWin_Right, wndpl.rcNormalPosition.right);
gMyApp.WriteProfileInt(kMainWinSection,
kMainWin_Bottom, wndpl.rcNormalPosition.bottom);
gMyApp.WriteProfileInt(kMainWinSection,
kMainWin_Cmd, wndpl.showCmd);
}
void MainWindow::RestoreWinPlacement()
{
RECT normPos;
normPos.left = gMyApp.GetProfileInt(kMainWinSection, kMainWin_Left, -1);
normPos.top = gMyApp.GetProfileInt(kMainWinSection, kMainWin_Top, -1);
normPos.right = gMyApp.GetProfileInt(kMainWinSection, kMainWin_Right, -1);
normPos.bottom = gMyApp.GetProfileInt(kMainWinSection, kMainWin_Bottom, -1);
int cmd = gMyApp.GetProfileInt(kMainWinSection, kMainWin_Cmd, -1);
if (normPos.left < 0 || normPos.top < 0 || normPos.right < 0 ||
normPos.bottom < 0 || cmd < 0) {
LOGI("Previous window placement not found.");
return;
}
POINT nopt;
nopt.x = nopt.y = -1;
// We need to set the placement for "normal", and then deal with
// maximized windows by having the MyApp ShowWindow() call pass the
// appropriate command. If we pass the correct normal rect here with
// the "maximized" command, we end up with a non-maximized window of
// maximum size. (If done correctly, you can maximize, quit, restart,
// and un-maximize back to the original size.)
WINDOWPLACEMENT wndpl;
wndpl.length = sizeof(wndpl);
wndpl.flags = 0;
wndpl.showCmd = SW_SHOWNORMAL;
wndpl.ptMinPosition = nopt;
wndpl.ptMaxPosition = nopt;
wndpl.rcNormalPosition = normPos;
LOGD("Restoring previous placement, cmd=%d", wndpl.showCmd);
SetWindowPlacement(&wndpl);
// Stomp on MyApp's show command. We don't want to start minimized,
// so switch to "normal" if that's set.
gMyApp.m_nCmdShow = (cmd == SW_SHOWMINIMIZED ? SW_SHOWNORMAL : cmd);
}
void MainWindow::DrawEmptyClientArea(CDC* pDC, const CRect& clientRect)
{
CBrush brush;

View File

@ -54,7 +54,7 @@ public:
/*
* Override the pre-create function to tweak the window style.
*/
BOOL PreCreateWindow(CREATESTRUCT& cs) override;
virtual BOOL PreCreateWindow(CREATESTRUCT& cs) override;
/*
* Override GetClientRect so we can factor in the status and tool bars.
@ -268,6 +268,7 @@ private:
// Command handlers
afx_msg int OnCreate(LPCREATESTRUCT lpcs);
afx_msg void OnClose();
afx_msg LONG OnLateInit(UINT, LONG);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnGetMinMaxInfo(MINMAXINFO* pMMI);
@ -489,6 +490,14 @@ private:
*/
void DrawEmptyClientArea(CDC* pDC, const CRect& clientRect);
/*
* Save/restore main window placement. The restore function will move
* the window if the previous placement is no longer visible (e.g. a
* secondary monitor was removed).
*/
void SaveWinPlacement();
void RestoreWinPlacement();
/*
* Extract a record to the temp folder and open it with a new instance of
* CiderPress. We might want to extract disk images as 2MG files to take

View File

@ -64,6 +64,16 @@ MyApp::~MyApp(void)
BOOL MyApp::InitInstance(void)
{
// This causes functions like SetProfileInt to use the registry rather
// than a .INI file. The registry key is "usually the name of a company".
// (Must do this before creating main window so we can restore the
// previous window position.)
#ifdef CAN_UPDATE_FILE_ASSOC
SetRegistryKey(fRegistry.GetAppRegistryKey());
#else
SetRegistryKey(L"faddenSoft");
#endif
// Create the main window.
m_pMainWnd = new MainWindow;
m_pMainWnd->ShowWindow(m_nCmdShow);
@ -92,14 +102,6 @@ BOOL MyApp::InitInstance(void)
LogModuleLocation(L"riched32.dll");
LogModuleLocation(L"msftedit.dll");
// This causes functions like SetProfileInt to use the registry rather
// than a .INI file. The registry key is "usually the name of a company".
#ifdef CAN_UPDATE_FILE_ASSOC
SetRegistryKey(fRegistry.GetAppRegistryKey());
#else
SetRegistryKey(L"faddenSoft");
#endif
//LOGI("Registry key is '%ls'", m_pszRegistryKey);
//LOGI("Profile name is '%ls'", m_pszProfileName);
LOGI("Short command line is '%ls'", m_lpCmdLine);