Skip to content
This repository was archived by the owner on Sep 2, 2021. It is now read-only.

Commit 4bc4bb4

Browse files
committed
Merge pull request #123 from adobe/randy/restore-window-position
windows: restore window position
2 parents 26ec63b + d4bd936 commit 4bc4bb4

File tree

1 file changed

+232
-5
lines changed

1 file changed

+232
-5
lines changed

appshell/cefclient_win.cpp

Lines changed: 232 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,30 @@ extern CefRefPtr<ClientHandler> g_handler;
5555
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") // NOLINT(whitespace/line_length)
5656
#endif
5757

58+
// Registry access functions
59+
void EnsureTrailingSeparator(LPWSTR pRet);
60+
void GetKey(LPCWSTR pBase, LPCWSTR pGroup, LPCWSTR pApp, LPCWSTR pFolder, LPWSTR pRet);
61+
bool GetRegistryInt(LPCWSTR pFolder, LPCWSTR pEntry, int* pDefault, int& ret);
62+
bool WriteRegistryInt (LPCWSTR pFolder, LPCWSTR pEntry, int val);
63+
64+
// Registry key strings
65+
#define PREF_APPSHELL_BASE L"Software"
66+
#define PREF_WINPOS_FOLDER L"Window Position"
67+
#define PREF_LEFT L"Left"
68+
#define PREF_TOP L"Top"
69+
#define PREF_WIDTH L"Width"
70+
#define PREF_HEIGHT L"Height"
71+
#define PREF_RESTORE_LEFT L"Restore Left"
72+
#define PREF_RESTORE_TOP L"Restore Top"
73+
#define PREF_RESTORE_RIGHT L"Restore Right"
74+
#define PREF_RESTORE_BOTTOM L"Restore Bottom"
75+
#define PREF_SHOWSTATE L"Show State"
76+
77+
// Window state functions
78+
void SaveWindowRect(HWND hWnd);
79+
void RestoreWindowRect(int& left, int& top, int& width, int& height, int& showCmd);
80+
void RestoreWindowPlacement(HWND hWnd, int showCmd);
81+
5882
// Program entry point function.
5983
int APIENTRY wWinMain(HINSTANCE hInstance,
6084
HINSTANCE hPrevInstance,
@@ -190,6 +214,193 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
190214
return result;
191215
}
192216

217+
// Add trailing separator, if necessary
218+
void EnsureTrailingSeparator(LPWSTR pRet)
219+
{
220+
if (!pRet)
221+
return;
222+
223+
int len = wcslen(pRet);
224+
if (len > 0 && wcscmp(&(pRet[len-1]), L"\\") != 0)
225+
{
226+
wcscat(pRet, L"\\");
227+
}
228+
}
229+
230+
// Helper method to build Registry Key string
231+
void GetKey(LPCWSTR pBase, LPCWSTR pGroup, LPCWSTR pApp, LPCWSTR pFolder, LPWSTR pRet)
232+
{
233+
// Check for required params
234+
ASSERT(pBase && pApp && pRet);
235+
if (!pBase || !pApp || !pRet)
236+
return;
237+
238+
// Base
239+
wcscpy(pRet, pBase);
240+
241+
// Group (optional)
242+
if (pGroup && (pGroup[0] != '\0'))
243+
{
244+
EnsureTrailingSeparator(pRet);
245+
wcscat(pRet, pGroup);
246+
}
247+
248+
// App name
249+
EnsureTrailingSeparator(pRet);
250+
wcscat(pRet, pApp);
251+
252+
// Folder (optional)
253+
if (pFolder && (pFolder[0] != '\0'))
254+
{
255+
EnsureTrailingSeparator(pRet);
256+
wcscat(pRet, pFolder);
257+
}
258+
}
259+
260+
// get integer value from registry key
261+
// caller can either use return value to determine success/fail, or pass a default to be used on fail
262+
bool GetRegistryInt(LPCWSTR pFolder, LPCWSTR pEntry, int* pDefault, int& ret)
263+
{
264+
HKEY hKey;
265+
bool result = false;
266+
267+
wchar_t key[MAX_PATH];
268+
key[0] = '\0';
269+
GetKey(PREF_APPSHELL_BASE, GROUP_NAME, APP_NAME, pFolder, (LPWSTR)&key);
270+
271+
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, (LPCWSTR)key, 0, KEY_READ, &hKey))
272+
{
273+
DWORD dwValue = 0;
274+
DWORD dwType = 0;
275+
DWORD dwCount = sizeof(DWORD);
276+
if (ERROR_SUCCESS == RegQueryValueEx(hKey, pEntry, NULL, &dwType, (LPBYTE)&dwValue, &dwCount))
277+
{
278+
result = true;
279+
ASSERT(dwType == REG_DWORD);
280+
ASSERT(dwCount == sizeof(dwValue));
281+
ret = (int)dwValue;
282+
}
283+
RegCloseKey(hKey);
284+
}
285+
286+
if (!result)
287+
{
288+
// couldn't read value, so use default, if specified
289+
if (pDefault)
290+
ret = *pDefault;
291+
}
292+
293+
return result;
294+
}
295+
296+
// write integer value to registry key
297+
bool WriteRegistryInt(LPCWSTR pFolder, LPCWSTR pEntry, int val)
298+
{
299+
HKEY hKey;
300+
bool result = false;
301+
302+
wchar_t key[MAX_PATH];
303+
key[0] = '\0';
304+
GetKey(PREF_APPSHELL_BASE, GROUP_NAME, APP_NAME, pFolder, (LPWSTR)&key);
305+
306+
if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, (LPCWSTR)key, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL))
307+
{
308+
DWORD dwCount = sizeof(int);
309+
if (ERROR_SUCCESS == RegSetValueEx(hKey, pEntry, 0, REG_DWORD, (LPBYTE)&val, dwCount))
310+
result = true;
311+
RegCloseKey(hKey);
312+
}
313+
314+
return result;
315+
}
316+
317+
void SaveWindowRect(HWND hWnd)
318+
{
319+
// Save position of active window
320+
if (!hWnd)
321+
return;
322+
323+
WINDOWPLACEMENT wp;
324+
memset(&wp, 0, sizeof(WINDOWPLACEMENT));
325+
wp.length = sizeof(WINDOWPLACEMENT);
326+
327+
if (GetWindowPlacement(hWnd, &wp))
328+
{
329+
// Only save window positions for "restored" and "maximized" states.
330+
// If window is closed while "minimized", we don't want it to open minimized
331+
// for next session, so don't update registry so it opens in previous state.
332+
if (wp.showCmd == SW_SHOWNORMAL || wp.showCmd == SW_SHOW || wp.showCmd == SW_MAXIMIZE)
333+
{
334+
RECT rect;
335+
if (GetWindowRect(hWnd, &rect))
336+
{
337+
WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_LEFT, rect.left);
338+
WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_TOP, rect.top);
339+
WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_WIDTH, rect.right - rect.left);
340+
WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_HEIGHT, rect.bottom - rect.top);
341+
}
342+
343+
if (wp.showCmd == SW_MAXIMIZE)
344+
{
345+
// When window is maximized, we also store the "restore" size
346+
WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_LEFT, wp.rcNormalPosition.left);
347+
WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_TOP, wp.rcNormalPosition.top);
348+
WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_RIGHT, wp.rcNormalPosition.right);
349+
WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_BOTTOM, wp.rcNormalPosition.bottom);
350+
}
351+
352+
// Maximize is the only special case we handle
353+
WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_SHOWSTATE,
354+
(wp.showCmd == SW_MAXIMIZE) ? SW_MAXIMIZE : SW_SHOW);
355+
}
356+
}
357+
}
358+
359+
void RestoreWindowRect(int& left, int& top, int& width, int& height, int& showCmd)
360+
{
361+
GetRegistryInt(PREF_WINPOS_FOLDER, PREF_LEFT, NULL, left);
362+
GetRegistryInt(PREF_WINPOS_FOLDER, PREF_TOP, NULL, top);
363+
GetRegistryInt(PREF_WINPOS_FOLDER, PREF_WIDTH, NULL, width);
364+
GetRegistryInt(PREF_WINPOS_FOLDER, PREF_HEIGHT, NULL, height);
365+
GetRegistryInt(PREF_WINPOS_FOLDER, PREF_SHOWSTATE, NULL, showCmd);
366+
}
367+
368+
void RestoreWindowPlacement(HWND hWnd, int showCmd)
369+
{
370+
if (!hWnd)
371+
return;
372+
373+
// If window is maximized, set the "restore" window position
374+
if (showCmd == SW_MAXIMIZE)
375+
{
376+
WINDOWPLACEMENT wp;
377+
wp.length = sizeof(WINDOWPLACEMENT);
378+
379+
wp.flags = 0;
380+
wp.showCmd = SW_MAXIMIZE;
381+
wp.ptMinPosition.x = -1;
382+
wp.ptMinPosition.y = -1;
383+
wp.ptMaxPosition.x = -1;
384+
wp.ptMaxPosition.y = -1;
385+
386+
wp.rcNormalPosition.left = CW_USEDEFAULT;
387+
wp.rcNormalPosition.top = CW_USEDEFAULT;
388+
wp.rcNormalPosition.right = CW_USEDEFAULT;
389+
wp.rcNormalPosition.bottom = CW_USEDEFAULT;
390+
391+
GetRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_LEFT, NULL, (int&)wp.rcNormalPosition.left);
392+
GetRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_TOP, NULL, (int&)wp.rcNormalPosition.top);
393+
GetRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_RIGHT, NULL, (int&)wp.rcNormalPosition.right);
394+
GetRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_BOTTOM, NULL, (int&)wp.rcNormalPosition.bottom);
395+
396+
// This returns an error code, but not sure what we could do on an error
397+
SetWindowPlacement(hWnd, &wp);
398+
}
399+
400+
ShowWindow(hWnd, showCmd);
401+
}
402+
403+
193404
//
194405
// FUNCTION: MyRegisterClass()
195406
//
@@ -247,14 +458,26 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) {
247458

248459
hInst = hInstance; // Store instance handle in our global variable
249460

250-
hWnd = CreateWindow(szWindowClass, szTitle,
251-
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, 0,
252-
CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
461+
// TODO: test this cases:
462+
// - window in secondary monitor when shutdown, disconnect secondary monitor, restart
463+
464+
int left = CW_USEDEFAULT;
465+
int top = CW_USEDEFAULT;
466+
int width = CW_USEDEFAULT;
467+
int height = CW_USEDEFAULT;
468+
int showCmd = SW_SHOW;
469+
RestoreWindowRect(left, top, width, height, showCmd);
470+
471+
DWORD styles = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
472+
if (showCmd == SW_MAXIMIZE)
473+
styles |= WS_MAXIMIZE;
474+
hWnd = CreateWindow(szWindowClass, szTitle, styles,
475+
left, top, width, height, NULL, NULL, hInstance, NULL);
253476

254477
if (!hWnd)
255478
return FALSE;
256479

257-
ShowWindow(hWnd, nCmdShow);
480+
RestoreWindowPlacement(hWnd, showCmd);
258481
UpdateWindow(hWnd);
259482

260483
return TRUE;
@@ -511,6 +734,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
511734

512735
case WM_CLOSE:
513736
if (g_handler.get()) {
737+
738+
HWND hWnd = GetActiveWindow();
739+
SaveWindowRect(hWnd);
740+
514741
// If we already initiated the browser closing, then let default window proc handle it.
515742
HWND browserHwnd = g_handler->GetBrowser()->GetHost()->GetWindowHandle();
516743
HANDLE closing = GetProp(browserHwnd, CLOSING_PROP);
@@ -568,4 +795,4 @@ CefString AppGetCachePath() {
568795
cachePath += L"\\" GROUP_NAME APP_NAME L"\\cef_data";
569796

570797
return CefString(cachePath);
571-
}
798+
}

0 commit comments

Comments
 (0)