From 989351a2edbe6f96cc64454cc52daff2cd5d85da Mon Sep 17 00:00:00 2001 From: bchintx Date: Wed, 11 Sep 2013 16:42:38 -0700 Subject: [PATCH 01/11] implement portable Brackets on Windows --- appshell/cefclient_win.cpp | 187 ++++++++++++++++++++++++++++-------- appshell/client_app.h | 1 + appshell/client_app_win.cpp | 42 +++++++- 3 files changed, 188 insertions(+), 42 deletions(-) diff --git a/appshell/cefclient_win.cpp b/appshell/cefclient_win.cpp index 97441e5ba..cf2004306 100644 --- a/appshell/cefclient_win.cpp +++ b/appshell/cefclient_win.cpp @@ -50,11 +50,16 @@ char szWorkingDir[MAX_PATH]; // The current working directory TCHAR szInitialUrl[MAX_PATH] = {0}; +bool gPortableInstall = false; // true if this is a portable install -- ie don't serialize anything outside of app folder +static RECT grectWindow; // persisted window position for next launch +static RECT grectRestore; // persisted restored window position if left maximized for next launch + // Forward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance, const cef_string_t& locale); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); +bool CheckIfPortableInstall(); // The global ClientHandler reference. extern CefRefPtr g_handler; @@ -184,6 +189,9 @@ int APIENTRY wWinMain(HINSTANCE hInstance, CefMainArgs main_args(hInstance); CefRefPtr app(new ClientApp); + // check if this is a portable install + gPortableInstall = CheckIfPortableInstall(); + // Execute the secondary process, if any. int exit_code = CefExecuteProcess(main_args, app.get()); if (exit_code >= 0) @@ -443,6 +451,114 @@ bool WriteRegistryInt(LPCWSTR pFolder, LPCWSTR pEntry, int val) return result; } +// persists window size and state for next launch +void WriteWindowPlacement(int showCmd) +{ + if (!gPortableInstall) + { + // for normal installations, serialize to the Registry + WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_LEFT, grectWindow.left); + WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_TOP, grectWindow.top); + WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_WIDTH, grectWindow.right - grectWindow.left); + WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_HEIGHT, grectWindow.bottom - grectWindow.top); + + WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_LEFT, grectRestore.left); + WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_TOP, grectRestore.top); + WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_RIGHT, grectRestore.right); + WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_BOTTOM, grectRestore.bottom); + + WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_SHOWSTATE, showCmd); + } + else + { + // for portable installations, serialize to a file in the app folder + std::wstring filename = ClientApp::AppGetSupportDirectory(); + filename += L"\\lastWindowState.dat"; + HANDLE hFile = ::CreateFile(filename.c_str(), GENERIC_WRITE, + FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE != hFile) + { + DWORD dwBytesWritten; + std::stringstream streambuf; + streambuf << grectWindow.left << ' '; + streambuf << grectWindow.top << ' '; + streambuf << grectWindow.right - grectWindow.left << ' '; + streambuf << grectWindow.bottom - grectWindow.top << ' '; + streambuf << grectRestore.left << ' '; + streambuf << grectRestore.top << ' '; + streambuf << grectRestore.right << ' '; + streambuf << grectRestore.bottom << ' '; + streambuf << showCmd; + std::string contents = streambuf.str(); + ::WriteFile(hFile, contents.c_str(), contents.length(), &dwBytesWritten, NULL); + + ::CloseHandle(hFile); + } + } +} + +// read window size and state persisted from previous launch +void ReadWindowPlacement(int& showCmd) +{ + ::SetRect(&grectWindow, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT); + ::SetRect(&grectRestore, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT); + showCmd = SW_SHOW; + + if (!gPortableInstall) + { + // for normal installations, serialize from the Registry + int ival; + GetRegistryInt(PREF_WINPOS_FOLDER, PREF_LEFT, NULL, ival); + grectWindow.left = ival; + GetRegistryInt(PREF_WINPOS_FOLDER, PREF_TOP, NULL, ival); + grectWindow.top = ival; + GetRegistryInt(PREF_WINPOS_FOLDER, PREF_WIDTH, NULL, ival); + grectWindow.right = ival - grectWindow.left; + GetRegistryInt(PREF_WINPOS_FOLDER, PREF_HEIGHT, NULL, ival); + grectWindow.bottom = ival - grectWindow.top; + + GetRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_LEFT, NULL, ival); + grectRestore.left = ival; + GetRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_TOP, NULL, ival); + grectRestore.top = ival; + GetRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_RIGHT, NULL, ival); + grectRestore.right = ival; + GetRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_BOTTOM, NULL, ival); + grectRestore.bottom = ival; + + GetRegistryInt(PREF_WINPOS_FOLDER, PREF_SHOWSTATE, NULL, showCmd); + } + else + { + // for portable installations, serialize from a file in the app folder + std::wstring filename = ClientApp::AppGetSupportDirectory(); + filename += L"\\lastWindowState.dat"; + HANDLE hFile = ::CreateFile(filename.c_str(), GENERIC_READ, + FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE != hFile) + { + DWORD dwFileSize = ::GetFileSize(hFile, NULL); + DWORD dwBytesRead; + BYTE* buffer = (BYTE*)malloc(dwFileSize); + if (buffer && ::ReadFile(hFile, buffer, dwFileSize, &dwBytesRead, NULL)) + { + std::string contents((char*)buffer, dwBytesRead); + std::stringstream streambuf(contents); + streambuf >> grectWindow.left; + streambuf >> grectWindow.top; + streambuf >> grectWindow.right; + streambuf >> grectWindow.bottom; + streambuf >> grectRestore.left; + streambuf >> grectRestore.top; + streambuf >> grectRestore.right; + streambuf >> grectRestore.bottom; + streambuf >> showCmd; + } + ::CloseHandle(hFile); + } + } +} + void SaveWindowRect(HWND hWnd) { // Save position of active window @@ -455,6 +571,10 @@ void SaveWindowRect(HWND hWnd) if (GetWindowPlacement(hWnd, &wp)) { + // only update the restore rect if we're currently maximized. + if (wp.showCmd == SW_MAXIMIZE) + ::CopyRect(&grectRestore, &wp.rcNormalPosition); + // Only save window positions for "restored" and "maximized" states. // If window is closed while "minimized", we don't want it to open minimized // for next session, so don't update registry so it opens in previous state. @@ -462,38 +582,17 @@ void SaveWindowRect(HWND hWnd) { RECT rect; if (GetWindowRect(hWnd, &rect)) - { - WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_LEFT, rect.left); - WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_TOP, rect.top); - WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_WIDTH, rect.right - rect.left); - WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_HEIGHT, rect.bottom - rect.top); - } + ::CopyRect(&grectWindow, &rect); - if (wp.showCmd == SW_MAXIMIZE) - { - // When window is maximized, we also store the "restore" size - WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_LEFT, wp.rcNormalPosition.left); - WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_TOP, wp.rcNormalPosition.top); - WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_RIGHT, wp.rcNormalPosition.right); - WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_BOTTOM, wp.rcNormalPosition.bottom); - } - - // Maximize is the only special case we handle - WriteRegistryInt(PREF_WINPOS_FOLDER, PREF_SHOWSTATE, - (wp.showCmd == SW_MAXIMIZE) ? SW_MAXIMIZE : SW_SHOW); + WriteWindowPlacement( + // Maximize is the only special case we handle + (wp.showCmd == SW_MAXIMIZE) ? SW_MAXIMIZE : SW_SHOW); } } } void RestoreWindowRect(int& left, int& top, int& width, int& height, int& showCmd) { - // Start with Registry data - GetRegistryInt(PREF_WINPOS_FOLDER, PREF_LEFT, NULL, left); - GetRegistryInt(PREF_WINPOS_FOLDER, PREF_TOP, NULL, top); - GetRegistryInt(PREF_WINPOS_FOLDER, PREF_WIDTH, NULL, width); - GetRegistryInt(PREF_WINPOS_FOLDER, PREF_HEIGHT, NULL, height); - GetRegistryInt(PREF_WINPOS_FOLDER, PREF_SHOWSTATE, NULL, showCmd); - // If window size has changed, we may need to alter window size HMONITOR hMonitor; MONITORINFO mi; @@ -569,15 +668,10 @@ void RestoreWindowPlacement(HWND hWnd, int showCmd) wp.ptMaxPosition.x = -1; wp.ptMaxPosition.y = -1; - wp.rcNormalPosition.left = CW_USEDEFAULT; - wp.rcNormalPosition.top = CW_USEDEFAULT; - wp.rcNormalPosition.right = CW_USEDEFAULT; - wp.rcNormalPosition.bottom = CW_USEDEFAULT; - - GetRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_LEFT, NULL, (int&)wp.rcNormalPosition.left); - GetRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_TOP, NULL, (int&)wp.rcNormalPosition.top); - GetRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_RIGHT, NULL, (int&)wp.rcNormalPosition.right); - GetRegistryInt(PREF_WINPOS_FOLDER, PREF_RESTORE_BOTTOM, NULL, (int&)wp.rcNormalPosition.bottom); + wp.rcNormalPosition.left = grectRestore.left; + wp.rcNormalPosition.top = grectRestore.top; + wp.rcNormalPosition.right = grectRestore.right; + wp.rcNormalPosition.bottom = grectRestore.bottom; // This returns an error code, but not sure what we could do on an error SetWindowPlacement(hWnd, &wp); @@ -637,11 +731,13 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { // TODO: test this cases: // - window in secondary monitor when shutdown, disconnect secondary monitor, restart - int left = CW_USEDEFAULT; - int top = CW_USEDEFAULT; - int width = CW_USEDEFAULT; - int height = CW_USEDEFAULT; - int showCmd = SW_SHOW; + int showCmd; + ReadWindowPlacement(showCmd); + + int left = grectWindow.left; + int top = grectWindow.top; + int width = grectWindow.left != CW_USEDEFAULT ? grectWindow.right - grectWindow.left : CW_USEDEFAULT; + int height = grectWindow.top != CW_USEDEFAULT ? grectWindow.bottom - grectWindow.top : CW_USEDEFAULT; RestoreWindowRect(left, top, width, height, showCmd); DWORD styles = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN; @@ -1064,3 +1160,16 @@ CefString AppGetProductVersionString() { s.append(version); return CefString(s); } + +// check if this is a portable installation +// to be a portable installation, the installer should write the empty file to the app folder +bool CheckIfPortableInstall() +{ + std::wstring filename = ClientApp::AppGetAppDirectory(); + filename += L"/isPortableInstall.dat"; + HANDLE hFile = ::CreateFile(filename.c_str(), GENERIC_READ, + FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + bool result = INVALID_HANDLE_VALUE != hFile; + ::CloseHandle(hFile); + return result; +} diff --git a/appshell/client_app.h b/appshell/client_app.h index 3388211fc..09ff08fe4 100644 --- a/appshell/client_app.h +++ b/appshell/client_app.h @@ -91,6 +91,7 @@ class ClientApp : public CefApp, double GetElapsedMilliseconds(); CefString GetCurrentLanguage(); std::string GetExtensionJSSource(); + static CefString AppGetAppDirectory(); static CefString AppGetSupportDirectory(); static CefString AppGetDocumentsDirectory(); diff --git a/appshell/client_app_win.cpp b/appshell/client_app_win.cpp index 0f312c09d..0af54ecb3 100644 --- a/appshell/client_app_win.cpp +++ b/appshell/client_app_win.cpp @@ -90,12 +90,48 @@ double ClientApp::GetElapsedMilliseconds() return (timeGetTime() - g_appStartupTime); } +extern bool gPortableInstall; // defined in cefclient_win.cpp + +// returns the directory to which the app has been installed +CefString ClientApp::AppGetAppDirectory() +{ + // find the full pathname of the app .exe + std::wstring appPath; + HMODULE hModule = ::GetModuleHandle(NULL); + if (hModule) + { + WCHAR filename[MAX_PATH+1] = {0}; + ::GetModuleFileName(hModule, filename, MAX_PATH); + appPath = filename; + + // strip off the filename and extension + int idx = appPath.rfind('\\'); + if (idx >= 0) + appPath = appPath.substr(0, idx); + } + + // Convert '\\' to '/' + replace(appPath.begin(), appPath.end(), '\\', '/'); + + return CefString(appPath); +} + CefString ClientApp::AppGetSupportDirectory() { - wchar_t dataPath[MAX_PATH]; - SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, dataPath); + std::wstring appSupportPath; + if (!gPortableInstall) + { + // for normal installations, use the user's APPDATA folder + wchar_t dataPath[MAX_PATH]; + SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, dataPath); + appSupportPath = dataPath; + } + else + { + // for portable installations, use the app's installed folder + appSupportPath = ClientApp::AppGetAppDirectory(); + } - std::wstring appSupportPath = dataPath; appSupportPath += L"\\" GROUP_NAME APP_NAME; // Convert '\\' to '/' From 502e06f6f4d413d5ccb1c3553b48bf363e1c21c4 Mon Sep 17 00:00:00 2001 From: Bryan Chin Date: Fri, 13 Sep 2013 16:52:58 -0500 Subject: [PATCH 02/11] simplify portable install filename --- appshell/cefclient_win.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appshell/cefclient_win.cpp b/appshell/cefclient_win.cpp index cf2004306..26b2929ba 100644 --- a/appshell/cefclient_win.cpp +++ b/appshell/cefclient_win.cpp @@ -1166,7 +1166,7 @@ CefString AppGetProductVersionString() { bool CheckIfPortableInstall() { std::wstring filename = ClientApp::AppGetAppDirectory(); - filename += L"/isPortableInstall.dat"; + filename += L"/makePortable"; HANDLE hFile = ::CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); bool result = INVALID_HANDLE_VALUE != hFile; From 8c0779ab19f44eb268225d36b990f645c53a1d77 Mon Sep 17 00:00:00 2001 From: Bryan Chin Date: Tue, 17 Sep 2013 17:58:05 -0500 Subject: [PATCH 03/11] implement portable install on Mac --- appshell/client_app.h | 1 + appshell/client_app_mac.mm | 49 ++++++++++++++++++++++++++++++++++---- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/appshell/client_app.h b/appshell/client_app.h index 09ff08fe4..8e7af842a 100644 --- a/appshell/client_app.h +++ b/appshell/client_app.h @@ -91,6 +91,7 @@ class ClientApp : public CefApp, double GetElapsedMilliseconds(); CefString GetCurrentLanguage(); std::string GetExtensionJSSource(); + static bool CheckIfPortableInstall(); static CefString AppGetAppDirectory(); static CefString AppGetSupportDirectory(); static CefString AppGetDocumentsDirectory(); diff --git a/appshell/client_app_mac.mm b/appshell/client_app_mac.mm index 51f20d290..3d73f7cbe 100644 --- a/appshell/client_app_mac.mm +++ b/appshell/client_app_mac.mm @@ -83,12 +83,51 @@ return result; } +// check if this is a portable installation +// which is marked by the existence of a file named "makePortable" in the same folder as .app. +bool ClientApp::CheckIfPortableInstall() +{ + // + std::string filename = ClientApp::AppGetAppDirectory(); + filename += "/makePortable"; + NSString * nsFilename = [NSString stringWithUTF8String:filename.c_str()]; + return [[NSFileManager defaultManager] fileExistsAtPath:nsFilename]; +} -CefString ClientApp::AppGetSupportDirectory() { - NSString *libraryDirectory = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - NSString *supportDirectory = [NSString stringWithFormat:@"%@/%@%@", libraryDirectory, GROUP_NAME, APP_NAME]; - - return CefString([supportDirectory UTF8String]); +// returns the directory to which the app has been installed +CefString ClientApp::AppGetAppDirectory() +{ + // find the path-only of Brackets.app. Need to iterate in case we're called from the helper.app. + NSString * applicationPath = [[NSBundle mainBundle] bundlePath]; + NSString * appFilename = [applicationPath lastPathComponent]; + while ([appFilename length] && ![appFilename isEqualToString:APP_NAME @".app"]) + { + applicationPath = [applicationPath stringByDeletingLastPathComponent]; + appFilename = [applicationPath lastPathComponent]; + } + applicationPath = [applicationPath stringByDeletingLastPathComponent]; + + return CefString([applicationPath UTF8String]); +} + +CefString ClientApp::AppGetSupportDirectory() +{ + if (!CheckIfPortableInstall()) + { + // for normal installations, use the Library folder + NSString *libraryDirectory = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0]; + NSString *supportDirectory = [NSString stringWithFormat:@"%@/%@%@", libraryDirectory, GROUP_NAME, APP_NAME]; + return CefString([supportDirectory UTF8String]); + } + else + { + // for portable installations, use the app's installed folder + std::string strAppDir = ClientApp::AppGetAppDirectory(); + strAppDir += "/"; + NSString * appDir = [NSString stringWithUTF8String:strAppDir.c_str()]; + appDir = [appDir stringByAppendingString:APP_NAME]; + return CefString([appDir UTF8String]); + } } CefString ClientApp::AppGetDocumentsDirectory() { From b722bd8ac10b3dd060cd7dda2b030febcffc9d77 Mon Sep 17 00:00:00 2001 From: Bryan Chin Date: Wed, 18 Sep 2013 17:36:23 -0500 Subject: [PATCH 04/11] re-indenting with spaces --- appshell/client_app_mac.mm | 59 +++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/appshell/client_app_mac.mm b/appshell/client_app_mac.mm index 3d73f7cbe..2289270e6 100644 --- a/appshell/client_app_mac.mm +++ b/appshell/client_app_mac.mm @@ -87,47 +87,46 @@ // which is marked by the existence of a file named "makePortable" in the same folder as .app. bool ClientApp::CheckIfPortableInstall() { - // - std::string filename = ClientApp::AppGetAppDirectory(); - filename += "/makePortable"; - NSString * nsFilename = [NSString stringWithUTF8String:filename.c_str()]; - return [[NSFileManager defaultManager] fileExistsAtPath:nsFilename]; + std::string filename = ClientApp::AppGetAppDirectory(); + filename += "/makePortable"; + NSString * nsFilename = [NSString stringWithUTF8String:filename.c_str()]; + return [[NSFileManager defaultManager] fileExistsAtPath:nsFilename]; } // returns the directory to which the app has been installed CefString ClientApp::AppGetAppDirectory() { - // find the path-only of Brackets.app. Need to iterate in case we're called from the helper.app. + // find the path-only of Brackets.app. Need to iterate in case we're called from the helper.app. NSString * applicationPath = [[NSBundle mainBundle] bundlePath]; - NSString * appFilename = [applicationPath lastPathComponent]; - while ([appFilename length] && ![appFilename isEqualToString:APP_NAME @".app"]) - { - applicationPath = [applicationPath stringByDeletingLastPathComponent]; - appFilename = [applicationPath lastPathComponent]; - } - applicationPath = [applicationPath stringByDeletingLastPathComponent]; + NSString * appFilename = [applicationPath lastPathComponent]; + while ([appFilename length] && ![appFilename isEqualToString:APP_NAME @".app"]) + { + applicationPath = [applicationPath stringByDeletingLastPathComponent]; + appFilename = [applicationPath lastPathComponent]; + } + applicationPath = [applicationPath stringByDeletingLastPathComponent]; - return CefString([applicationPath UTF8String]); + return CefString([applicationPath UTF8String]); } CefString ClientApp::AppGetSupportDirectory() { - if (!CheckIfPortableInstall()) - { - // for normal installations, use the Library folder - NSString *libraryDirectory = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - NSString *supportDirectory = [NSString stringWithFormat:@"%@/%@%@", libraryDirectory, GROUP_NAME, APP_NAME]; - return CefString([supportDirectory UTF8String]); - } - else - { - // for portable installations, use the app's installed folder - std::string strAppDir = ClientApp::AppGetAppDirectory(); - strAppDir += "/"; - NSString * appDir = [NSString stringWithUTF8String:strAppDir.c_str()]; - appDir = [appDir stringByAppendingString:APP_NAME]; - return CefString([appDir UTF8String]); - } + if (!CheckIfPortableInstall()) + { + // for normal installations, use the Library folder + NSString *libraryDirectory = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0]; + NSString *supportDirectory = [NSString stringWithFormat:@"%@/%@%@", libraryDirectory, GROUP_NAME, APP_NAME]; + return CefString([supportDirectory UTF8String]); + } + else + { + // for portable installations, use the app's installed folder + std::string strAppDir = ClientApp::AppGetAppDirectory(); + strAppDir += "/"; + NSString * appDir = [NSString stringWithUTF8String:strAppDir.c_str()]; + appDir = [appDir stringByAppendingString:APP_NAME]; + return CefString([appDir UTF8String]); + } } CefString ClientApp::AppGetDocumentsDirectory() { From ce581d29b4806c92a529331c4d2afb56e7605716 Mon Sep 17 00:00:00 2001 From: Bryan Chin Date: Wed, 18 Sep 2013 17:42:37 -0500 Subject: [PATCH 05/11] re-indenting with spaces --- appshell/client_app_win.cpp | 58 ++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/appshell/client_app_win.cpp b/appshell/client_app_win.cpp index 0af54ecb3..ba3bf5f80 100644 --- a/appshell/client_app_win.cpp +++ b/appshell/client_app_win.cpp @@ -95,43 +95,43 @@ extern bool gPortableInstall; // defined in cefclient_win.cpp // returns the directory to which the app has been installed CefString ClientApp::AppGetAppDirectory() { - // find the full pathname of the app .exe - std::wstring appPath; - HMODULE hModule = ::GetModuleHandle(NULL); - if (hModule) - { - WCHAR filename[MAX_PATH+1] = {0}; - ::GetModuleFileName(hModule, filename, MAX_PATH); - appPath = filename; - - // strip off the filename and extension - int idx = appPath.rfind('\\'); - if (idx >= 0) - appPath = appPath.substr(0, idx); - } + // find the full pathname of the app .exe + std::wstring appPath; + HMODULE hModule = ::GetModuleHandle(NULL); + if (hModule) + { + WCHAR filename[MAX_PATH+1] = {0}; + ::GetModuleFileName(hModule, filename, MAX_PATH); + appPath = filename; + + // strip off the filename and extension + int idx = appPath.rfind('\\'); + if (idx >= 0) + appPath = appPath.substr(0, idx); + } // Convert '\\' to '/' replace(appPath.begin(), appPath.end(), '\\', '/'); - return CefString(appPath); + return CefString(appPath); } CefString ClientApp::AppGetSupportDirectory() { - std::wstring appSupportPath; - if (!gPortableInstall) - { - // for normal installations, use the user's APPDATA folder - wchar_t dataPath[MAX_PATH]; - SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, dataPath); - appSupportPath = dataPath; - } - else - { - // for portable installations, use the app's installed folder - appSupportPath = ClientApp::AppGetAppDirectory(); - } - + std::wstring appSupportPath; + if (!gPortableInstall) + { + // for normal installations, use the user's APPDATA folder + wchar_t dataPath[MAX_PATH]; + SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, dataPath); + appSupportPath = dataPath; + } + else + { + // for portable installations, use the app's installed folder + appSupportPath = ClientApp::AppGetAppDirectory(); + } + appSupportPath += L"\\" GROUP_NAME APP_NAME; // Convert '\\' to '/' From 698f6f6f61af8ac6eccf4d57e6a0591be0bf98d3 Mon Sep 17 00:00:00 2001 From: Bryan Chin Date: Thu, 19 Sep 2013 23:18:14 -0500 Subject: [PATCH 06/11] refactoring --- appshell/cefclient_win.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/appshell/cefclient_win.cpp b/appshell/cefclient_win.cpp index 1c0cc716e..32b391ce6 100644 --- a/appshell/cefclient_win.cpp +++ b/appshell/cefclient_win.cpp @@ -40,9 +40,6 @@ static char szWorkingDir[MAX_PATH]; // The current working directory static wchar_t szInitialUrl[MAX_PATH] = {0}; -static RECT grectWindow; // persisted window position for next launch -static RECT grectRestore; // persisted restored window position if left maximized for next launch - // Forward declarations of functions included in this code module: BOOL InitInstance(HINSTANCE, int); @@ -278,7 +275,6 @@ int APIENTRY wWinMain(HINSTANCE hInstance, return result; } - // // FUNCTION: InitInstance(HINSTANCE, int) // From 92c9415e86de1db885216cbf746fba9d544ce7fc Mon Sep 17 00:00:00 2001 From: Bryan Chin Date: Thu, 19 Sep 2013 23:41:20 -0500 Subject: [PATCH 07/11] fixing merge from master on Mac --- appshell/client_app_mac.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appshell/client_app_mac.mm b/appshell/client_app_mac.mm index 2289270e6..2378ca7da 100644 --- a/appshell/client_app_mac.mm +++ b/appshell/client_app_mac.mm @@ -85,7 +85,7 @@ // check if this is a portable installation // which is marked by the existence of a file named "makePortable" in the same folder as .app. -bool ClientApp::CheckIfPortableInstall() +bool ClientApp::IsPortableInstall() { std::string filename = ClientApp::AppGetAppDirectory(); filename += "/makePortable"; @@ -111,7 +111,7 @@ CefString ClientApp::AppGetSupportDirectory() { - if (!CheckIfPortableInstall()) + if (!IsPortableInstall()) { // for normal installations, use the Library folder NSString *libraryDirectory = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0]; From 080a162e41ee8feb320c90bd639982c7d338d8c4 Mon Sep 17 00:00:00 2001 From: Bryan Chin Date: Thu, 31 Jul 2014 14:55:27 -0500 Subject: [PATCH 08/11] changes per code review --- appshell/cef_main_window.cpp | 70 +++++++++++++++++++----------------- appshell/cef_main_window.h | 2 +- appshell/client_app.h | 1 + appshell/client_app_mac.mm | 14 ++++++-- appshell/client_app_win.cpp | 14 ++++++-- appshell/config.h | 7 ++++ 6 files changed, 71 insertions(+), 37 deletions(-) diff --git a/appshell/cef_main_window.cpp b/appshell/cef_main_window.cpp index 3a9926b04..55230c0fe 100644 --- a/appshell/cef_main_window.cpp +++ b/appshell/cef_main_window.cpp @@ -32,6 +32,15 @@ extern HINSTANCE hInst; extern CefRefPtr g_handler; +// portable build file structure +typedef struct { + char szSignature[18]; // MAKEPORTABLE_BRACKETS_SIGNATURE_STRING + unsigned short uVersion; // current file version + RECT rcWindow; + RECT rcRestored; + UINT showCmd; +} sCefMainWindowData; + // constants static const wchar_t kWindowClassname[] = L"CEFCLIENT"; static const wchar_t kWindowPostionFolder[] = L"Window Position"; @@ -326,26 +335,22 @@ void cef_main_window::SaveWindowRestoreRect() else { // for portable installations, serialize to a file in the app folder - std::wstring filename = ClientApp::AppGetSupportDirectory(); - filename += L"\\lastWindowState.dat"; + sCefMainWindowData data; + memset(&data, 0, sizeof(sCefMainWindowData)); + strcpy(data.szSignature, MAKEPORTABLE_BRACKETS_SIGNATURE_STRING); + data.uVersion = MAKEPORTABLE_BRACKETS_VERSION_CURRENT; + data.rcWindow = mWindowRect; + data.rcRestored = mRestoredRect; + data.showCmd = wp.showCmd; + + std::wstring filename; + ClientApp::GetPortableInstallFilename(filename); HANDLE hFile = ::CreateFile(filename.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != hFile) { - DWORD dwBytesWritten; - std::stringstream streambuf; - streambuf << mWindowRect.left << ' '; - streambuf << mWindowRect.top << ' '; - streambuf << mWindowRect.right << ' '; - streambuf << mWindowRect.bottom << ' '; - streambuf << mRestoredRect.left << ' '; - streambuf << mRestoredRect.top << ' '; - streambuf << mRestoredRect.right << ' '; - streambuf << mRestoredRect.bottom << ' '; - streambuf << wp.showCmd; - std::string contents = streambuf.str(); - ::WriteFile(hFile, contents.c_str(), contents.length(), &dwBytesWritten, NULL); - + DWORD dwBytesWritten = 0L; + ::WriteFile(hFile, (LPVOID)&data, sizeof(data), &dwBytesWritten, NULL); ::CloseHandle(hFile); } } @@ -381,28 +386,29 @@ void cef_main_window::LoadWindowRestoreRect(int& showCmd) else { // for portable installations, serialize to a file in the app folder - std::wstring filename = ClientApp::AppGetSupportDirectory(); - filename += L"\\lastWindowState.dat"; + std::wstring filename; + ClientApp::GetPortableInstallFilename(filename); HANDLE hFile = ::CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != hFile) { DWORD dwFileSize = ::GetFileSize(hFile, NULL); DWORD dwBytesRead; - BYTE* buffer = (BYTE*)malloc(dwFileSize); - if (buffer && ::ReadFile(hFile, buffer, dwFileSize, &dwBytesRead, NULL)) + sCefMainWindowData data; + if ((sizeof(sCefMainWindowData) == dwFileSize) + && ::ReadFile(hFile, (LPVOID)&data, sizeof(sCefMainWindowData), &dwBytesRead, NULL) + && (dwBytesRead == sizeof(sCefMainWindowData)) + && (strcmp(data.szSignature, MAKEPORTABLE_BRACKETS_SIGNATURE_STRING) == 0)) { - std::string contents((char*)buffer, dwBytesRead); - std::stringstream streambuf(contents); - streambuf >> mWindowRect.left; - streambuf >> mWindowRect.top; - streambuf >> mWindowRect.right; - streambuf >> mWindowRect.bottom; - streambuf >> mRestoredRect.left; - streambuf >> mRestoredRect.top; - streambuf >> mRestoredRect.right; - streambuf >> mRestoredRect.bottom; - streambuf >> showCmd; + if (data.uVersion <= MAKEPORTABLE_BRACKETS_VERSION_1) + { + mWindowRect = data.rcWindow; + mRestoredRect = data.rcRestored; + showCmd = data.showCmd; + } + + // future version struct additions go here... + // if (data.uVersion <= MAKEPORTABLE_BRACKETS_VERSION_xx) { } } ::CloseHandle(hFile); } @@ -411,7 +417,7 @@ void cef_main_window::LoadWindowRestoreRect(int& showCmd) // Initialization helper -- // Loads the Restores data and positions the window in its previously saved state -void cef_main_window::RestoreWindowPlacement(const int showCmd) +void cef_main_window::RestoreWindowPlacement(int showCmd) { if (showCmd == SW_MAXIMIZE) { diff --git a/appshell/cef_main_window.h b/appshell/cef_main_window.h index 4f5efada2..ca3f76a98 100644 --- a/appshell/cef_main_window.h +++ b/appshell/cef_main_window.h @@ -46,7 +46,7 @@ class cef_main_window : public cef_host_window // Initalization - Protected Members void SaveWindowRestoreRect(); void LoadWindowRestoreRect(int& showCmd); - void RestoreWindowPlacement(const int showCmd); + void RestoreWindowPlacement(int showCmd); // Message Handlers BOOL HandleEraseBackground(HDC hdc); diff --git a/appshell/client_app.h b/appshell/client_app.h index bc5e0de5d..5cc1f1253 100644 --- a/appshell/client_app.h +++ b/appshell/client_app.h @@ -92,6 +92,7 @@ class ClientApp : public CefApp, CefString GetCurrentLanguage(); std::string GetExtensionJSSource(); static bool IsPortableInstall(); + static void GetPortableInstallFilename(std::wstring& filename); static CefString AppGetAppDirectory(); static CefString AppGetSupportDirectory(); static CefString AppGetDocumentsDirectory(); diff --git a/appshell/client_app_mac.mm b/appshell/client_app_mac.mm index 2378ca7da..22fdd3ba5 100644 --- a/appshell/client_app_mac.mm +++ b/appshell/client_app_mac.mm @@ -87,12 +87,22 @@ // which is marked by the existence of a file named "makePortable" in the same folder as .app. bool ClientApp::IsPortableInstall() { - std::string filename = ClientApp::AppGetAppDirectory(); - filename += "/makePortable"; + std::string filename; + GetPortableInstallFilename(filename); NSString * nsFilename = [NSString stringWithUTF8String:filename.c_str()]; return [[NSFileManager defaultManager] fileExistsAtPath:nsFilename]; } +// return the name of the portable install data file +void ClientApp::GetPortableInstallFilename(std::wstring& filename) +{ + // the existence of this file in the same folder as the Brackets application will + // cause the application to be run in a "portable" state + filename = ClientApp::AppGetAppDirectory(); + filename += L"/"; + filename += MAKEPORTABLE_BRACKETS_FILENAME; +} + // returns the directory to which the app has been installed CefString ClientApp::AppGetAppDirectory() { diff --git a/appshell/client_app_win.cpp b/appshell/client_app_win.cpp index a303d35c6..a24eb8505 100644 --- a/appshell/client_app_win.cpp +++ b/appshell/client_app_win.cpp @@ -161,8 +161,8 @@ bool ClientApp::IsPortableInstall() if (isPortableInstall == UNINITIALIZED) { - std::wstring filename = ClientApp::AppGetAppDirectory(); - filename += L"/makePortable"; + std::wstring filename; + GetPortableInstallFilename(filename); HANDLE hFile = ::CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); isPortableInstall = (INVALID_HANDLE_VALUE != hFile) ? ISPORTABLE : ISNOTPORTABLE; @@ -170,3 +170,13 @@ bool ClientApp::IsPortableInstall() } return (isPortableInstall == ISPORTABLE) ? true : false; } + +// return the name of the portable install data file +void ClientApp::GetPortableInstallFilename(std::wstring& filename) +{ + // the existence of this file in the same folder as the Brackets application will + // cause the application to be run in a "portable" state + filename = ClientApp::AppGetAppDirectory(); + filename += L"/"; + filename += MAKEPORTABLE_BRACKETS_FILENAME; +} \ No newline at end of file diff --git a/appshell/config.h b/appshell/config.h index 645b5fe9e..b41f45c1e 100644 --- a/appshell/config.h +++ b/appshell/config.h @@ -72,3 +72,10 @@ #define CUSTOM_TRAFFIC_LIGHTS #define LIGHT_CAPTION_TEXT +// filename of Brackets' make portable switch +// the existence of this file in the same folder as the Brackets application will +// cause the application to be run in a "portable" state +#define MAKEPORTABLE_BRACKETS_FILENAME L"portable" +#define MAKEPORTABLE_BRACKETS_SIGNATURE_STRING "BracketsPortable" +#define MAKEPORTABLE_BRACKETS_VERSION_1 1 +#define MAKEPORTABLE_BRACKETS_VERSION_CURRENT MAKEPORTABLE_BRACKETS_VERSION_1 From 0537c9f67a1494f9d2214d083e4b2aae6ff0bb9f Mon Sep 17 00:00:00 2001 From: Bryan Chin Date: Tue, 12 Aug 2014 18:10:08 -0500 Subject: [PATCH 09/11] fixing Mac implmentation w/ code review requested changes --- appshell/client_app.h | 8 +++++++- appshell/client_app_mac.mm | 6 +++--- appshell/client_app_win.cpp | 2 +- appshell/config.h | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/appshell/client_app.h b/appshell/client_app.h index 5cc1f1253..a0bc1acef 100644 --- a/appshell/client_app.h +++ b/appshell/client_app.h @@ -92,7 +92,13 @@ class ClientApp : public CefApp, CefString GetCurrentLanguage(); std::string GetExtensionJSSource(); static bool IsPortableInstall(); - static void GetPortableInstallFilename(std::wstring& filename); + static void GetPortableInstallFilename( +#ifdef OS_WIN + std::wstring& filename +#else + std::string& filename +#endif //OS_WIN + ); static CefString AppGetAppDirectory(); static CefString AppGetSupportDirectory(); static CefString AppGetDocumentsDirectory(); diff --git a/appshell/client_app_mac.mm b/appshell/client_app_mac.mm index 22fdd3ba5..90e189b99 100644 --- a/appshell/client_app_mac.mm +++ b/appshell/client_app_mac.mm @@ -94,12 +94,12 @@ } // return the name of the portable install data file -void ClientApp::GetPortableInstallFilename(std::wstring& filename) +void ClientApp::GetPortableInstallFilename(std::string& filename) { // the existence of this file in the same folder as the Brackets application will // cause the application to be run in a "portable" state filename = ClientApp::AppGetAppDirectory(); - filename += L"/"; + filename += "/"; filename += MAKEPORTABLE_BRACKETS_FILENAME; } @@ -142,4 +142,4 @@ CefString ClientApp::AppGetDocumentsDirectory() { NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; return CefString([documentsDirectory UTF8String]); -} \ No newline at end of file +} diff --git a/appshell/client_app_win.cpp b/appshell/client_app_win.cpp index a24eb8505..e7179b070 100644 --- a/appshell/client_app_win.cpp +++ b/appshell/client_app_win.cpp @@ -178,5 +178,5 @@ void ClientApp::GetPortableInstallFilename(std::wstring& filename) // cause the application to be run in a "portable" state filename = ClientApp::AppGetAppDirectory(); filename += L"/"; - filename += MAKEPORTABLE_BRACKETS_FILENAME; + filename += L MAKEPORTABLE_BRACKETS_FILENAME; } \ No newline at end of file diff --git a/appshell/config.h b/appshell/config.h index b41f45c1e..ee48a3569 100644 --- a/appshell/config.h +++ b/appshell/config.h @@ -75,7 +75,7 @@ // filename of Brackets' make portable switch // the existence of this file in the same folder as the Brackets application will // cause the application to be run in a "portable" state -#define MAKEPORTABLE_BRACKETS_FILENAME L"portable" +#define MAKEPORTABLE_BRACKETS_FILENAME "portable" #define MAKEPORTABLE_BRACKETS_SIGNATURE_STRING "BracketsPortable" #define MAKEPORTABLE_BRACKETS_VERSION_1 1 #define MAKEPORTABLE_BRACKETS_VERSION_CURRENT MAKEPORTABLE_BRACKETS_VERSION_1 From dcd0165dac083614f36b9188ca9d162beb04924a Mon Sep 17 00:00:00 2001 From: Bryan Chin Date: Tue, 12 Aug 2014 18:19:57 -0500 Subject: [PATCH 10/11] correcting Windows build error --- appshell/client_app_win.cpp | 2 +- appshell/config.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/appshell/client_app_win.cpp b/appshell/client_app_win.cpp index e7179b070..a24eb8505 100644 --- a/appshell/client_app_win.cpp +++ b/appshell/client_app_win.cpp @@ -178,5 +178,5 @@ void ClientApp::GetPortableInstallFilename(std::wstring& filename) // cause the application to be run in a "portable" state filename = ClientApp::AppGetAppDirectory(); filename += L"/"; - filename += L MAKEPORTABLE_BRACKETS_FILENAME; + filename += MAKEPORTABLE_BRACKETS_FILENAME; } \ No newline at end of file diff --git a/appshell/config.h b/appshell/config.h index ee48a3569..b9da9fe5e 100644 --- a/appshell/config.h +++ b/appshell/config.h @@ -75,7 +75,11 @@ // filename of Brackets' make portable switch // the existence of this file in the same folder as the Brackets application will // cause the application to be run in a "portable" state +#ifdef OS_WIN +#define MAKEPORTABLE_BRACKETS_FILENAME L"portable" +#else #define MAKEPORTABLE_BRACKETS_FILENAME "portable" +#endif //OS_WIN #define MAKEPORTABLE_BRACKETS_SIGNATURE_STRING "BracketsPortable" #define MAKEPORTABLE_BRACKETS_VERSION_1 1 #define MAKEPORTABLE_BRACKETS_VERSION_CURRENT MAKEPORTABLE_BRACKETS_VERSION_1 From 0bcc6ae5fa313cf536db474c92f93c25bdf283d7 Mon Sep 17 00:00:00 2001 From: Bryan Chin Date: Fri, 19 Dec 2014 17:14:56 -0600 Subject: [PATCH 11/11] changes per code review --- appshell/client_app.h | 2 +- appshell/client_app_win.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/appshell/client_app.h b/appshell/client_app.h index a0bc1acef..d1ea56e01 100644 --- a/appshell/client_app.h +++ b/appshell/client_app.h @@ -97,7 +97,7 @@ class ClientApp : public CefApp, std::wstring& filename #else std::string& filename -#endif //OS_WIN +#endif ); static CefString AppGetAppDirectory(); static CefString AppGetSupportDirectory(); diff --git a/appshell/client_app_win.cpp b/appshell/client_app_win.cpp index a24eb8505..1cecce497 100644 --- a/appshell/client_app_win.cpp +++ b/appshell/client_app_win.cpp @@ -168,7 +168,7 @@ bool ClientApp::IsPortableInstall() isPortableInstall = (INVALID_HANDLE_VALUE != hFile) ? ISPORTABLE : ISNOTPORTABLE; ::CloseHandle(hFile); } - return (isPortableInstall == ISPORTABLE) ? true : false; + return (isPortableInstall == ISPORTABLE); } // return the name of the portable install data file