diff --git a/README.md b/README.md index 88d032c57..bfa87b549 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,30 @@ ## Overview -This is the new CEF3-based application shell for [Brackets](https://github.com/adobe/brackets). This replaces the old [brackets-app](https://github.com/adobe/brackets-app) shell. +This is the new CEF3-based application shell for [Brackets](https://github.com/adobe/brackets). +This replaces the old [brackets-app](https://github.com/adobe/brackets-app) shell. -Please read the main [README in the brackets repo](https://github.com/adobe/brackets/blob/master/README.md) for general information about Brackets. +Please read the main [README in the brackets repo](https://github.com/adobe/brackets/blob/master/README.md) +for general information about Brackets. -If you are interested in contributing to this shell, let us know on the [brackets-dev Google Group](http://groups.google.com/group/brackets-dev), or on the [#brackets channel on freenode](http://webchat.freenode.net/?channels=brackets). +If you are interested in contributing to this shell, let us know on the +[brackets-dev Google Group](http://groups.google.com/group/brackets-dev), +or on the [#brackets channel on freenode](http://webchat.freenode.net/?channels=brackets). -If you run into any issues with this new shell, please file a bug in the [brackets issue tracker](https://github.com/adobe/brackets/issues). +If you run into any issues with this new shell, please file a bug in the +[brackets issue tracker](https://github.com/adobe/brackets/issues). ## Running -[Download](https://github.com/adobe/brackets-shell/downloads) the .zip file for your platform (there are separate downloads for Mac and Win). +NOTE: There are no downloads for the brackets-shell. You either need to +build from source, or grab the [latest Brackets installer](https://github.com/adobe/brackets/downloads) +and run the shell from that. -NOTE: The downloads do **not** contain the html/css/javascript files used for Brackets. You will need to get those separately by cloning (or downloading) the [brackets repo](https://github.com/adobe/brackets). +When the app is launched, it first looks for an index.html file in the following locations: +* Mac - Brackets.app/Contents/dev/src/index.html, Brackets.app/Contents/www/index.html +* Win - dev/src/index.html, www/index.html (these folders must be in the same folder as Brackets.exe) -When the app is launched, it first looks for an index.html file in the following location: -* Mac - Brackets.app/Contents/www/index.html -* Win - www/index.html (the www folder must be in the same folder as Brackets.exe) - -If the index.html can't be found, you'll be prompted to find the brackets index.html file. Make sure you select the brackets/src/index.html file, and *not* some other file. This location is remembered for subsequent launches. If you want to point to a *different* index.html file, hold down the shift key while launching and you will get the prompt again. If you want to clear the saved file location, hold down the Option (mac) or Control (win) key while launching. - -NOTE: You need to hold down these modifier keys **before** launching Brackets. If you get a security dialog, make sure you continue to hold the modifier key after dismissing the dialog. +If the index.html can't be found, you'll be prompted to find the brackets index.html file. +Make sure you select the brackets/src/index.html file, and *not* some other file. The preferences are stored in `{USER}/Library/Application Support/Brackets/cef_data` on the mac and `{USER}\AppData\Roaming\Brackets\cef_data` on Windows. diff --git a/appshell/appshell_extensions_win.cpp b/appshell/appshell_extensions_win.cpp index ece231ff0..e198cd62a 100644 --- a/appshell/appshell_extensions_win.cpp +++ b/appshell/appshell_extensions_win.cpp @@ -43,6 +43,7 @@ int ConvertErrnoCode(int errorCode, bool isReading = true); int ConvertWinErrorCode(int errorCode, bool isReading = true); static std::wstring GetPathToLiveBrowser(); static bool ConvertToShortPathName(std::wstring & path); +time_t FiletimeToTime(FILETIME const& ft); /////////////////////////////////////////////////////////////////////////////// @@ -272,7 +273,27 @@ static int CALLBACK SetInitialPathCallback(HWND hWnd, UINT uMsg, LPARAM lParam, static std::wstring GetPathToLiveBrowser() { - // Chrome.exe is at C:\Users\{USERNAME}\AppData\Local\Google\Chrome\Application\chrome.exe + HKEY hKey; + + // First, look at the "App Paths" registry key for a "chrome.exe" entry. This only + // checks for installs for all users. If Chrome is only installed for the current user, + // we fall back to the code below. + if (ERROR_SUCCESS == RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe", + 0, KEY_READ, &hKey)) { + wchar_t wpath[MAX_PATH] = {0}; + + DWORD length = MAX_PATH; + RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)wpath, &length); + RegCloseKey(hKey); + + return std::wstring(wpath); + } + + // We didn't get an "App Paths" entry. This could be because Chrome was only installed for + // the current user, or because Chrome isn't installed at all. + // Look for Chrome.exe at C:\Users\{USERNAME}\AppData\Local\Google\Chrome\Application\chrome.exe TCHAR localAppPath[MAX_PATH] = {0}; SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, localAppPath); std::wstring appPath(localAppPath); @@ -297,16 +318,8 @@ static bool ConvertToShortPathName(std::wstring & path) int32 OpenLiveBrowser(ExtensionString argURL, bool enableRemoteDebugging) { std::wstring appPath = GetPathToLiveBrowser(); - - //When launching the app, we need to be careful about spaces in the path. A safe way to do this - //is to use the shortpath. It doesn't look as nice, but it always works and never has a space - if( !ConvertToShortPathName(appPath) ) { - //If the shortpath failed, we need to bail since we don't know what to call now - return ConvertWinErrorCode(GetLastError()); - } - - std::wstring args = appPath; + if (enableRemoteDebugging) args += L" --remote-debugging-port=9222 --allow-file-access-from-files "; else @@ -373,7 +386,7 @@ int32 OpenURLInDefaultBrowser(ExtensionString url) return NO_ERROR; } -int32 ShowOpenDialog(bool allowMulitpleSelection, +int32 ShowOpenDialog(bool allowMultipleSelection, bool chooseDirectory, ExtensionString title, ExtensionString initialDirectory, @@ -402,10 +415,11 @@ int32 ShowOpenDialog(bool allowMulitpleSelection, } */ - if (chooseDirectory) { - // SHBrowseForFolder can handle Windows path only, not Unix path. - ConvertToNativePath(initialDirectory); + // SHBrowseForFolder can handle Windows path only, not Unix path. + // ofn.lpstrInitialDir also needs Windows path on XP and not Unix path. + ConvertToNativePath(initialDirectory); + if (chooseDirectory) { BROWSEINFO bi = {0}; bi.hwndOwner = GetActiveWindow(); bi.lpszTitle = title.c_str(); @@ -445,11 +459,11 @@ int32 ShowOpenDialog(bool allowMulitpleSelection, ofn.lpstrInitialDir = initialDirectory.c_str(); ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_EXPLORER; - if (allowMulitpleSelection) + if (allowMultipleSelection) ofn.Flags |= OFN_ALLOWMULTISELECT; if (GetOpenFileName(&ofn)) { - if (allowMulitpleSelection) { + if (allowMultipleSelection) { // Multiple selection encodes the files differently // If multiple files are selected, the first null terminator @@ -550,17 +564,12 @@ int32 GetFileModificationTime(ExtensionString filename, uint32& modtime, bool& i isDir = ((dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0); - // Remove trailing "/", if present. _wstat will fail with a "file not found" - // error if a directory has a trailing '/' in the name. - if (filename[filename.length() - 1] == '/') - filename[filename.length() - 1] = 0; - - struct _stat buffer; - if(_wstat(filename.c_str(), &buffer) == -1) { - return ConvertErrnoCode(errno); + WIN32_FILE_ATTRIBUTE_DATA fad; + if (!GetFileAttributesEx(filename.c_str(), GetFileExInfoStandard, &fad)) { + return ConvertWinErrorCode(GetLastError()); } - modtime = buffer.st_mtime; + modtime = FiletimeToTime(fad.ftLastWriteTime); return NO_ERROR; } @@ -736,6 +745,25 @@ int ConvertWinErrorCode(int errorCode, bool isReading) } } +/** + * Convert a FILETIME (number of 100 nanosecond intervals since Jan 1 1601) + * to time_t (number of seconds since Jan 1 1970) + */ +time_t FiletimeToTime(FILETIME const& ft) { + ULARGE_INTEGER ull; + ull.LowPart = ft.dwLowDateTime; + ull.HighPart = ft.dwHighDateTime; + + // Convert the FILETIME from 100 nanosecond intervals into seconds + // and then subtract the number of seconds between + // Jan 1 1601 and Jan 1 1970 + + const int64 NANOSECOND_INTERVALS = 10000000ULL; + const int64 SECONDS_FROM_JAN_1_1601_TO_JAN_1_1970 = 11644473600ULL; + + return ull.QuadPart / NANOSECOND_INTERVALS - SECONDS_FROM_JAN_1_1601_TO_JAN_1_1970; +} + int32 ShowFolderInOSWindow(ExtensionString pathname) { ShellExecute(NULL, L"open", pathname.c_str(), NULL, NULL, SW_SHOWDEFAULT); return NO_ERROR; diff --git a/appshell/cefclient.cpp b/appshell/cefclient.cpp index f17ce0f2a..f2ca1bfc8 100644 --- a/appshell/cefclient.cpp +++ b/appshell/cefclient.cpp @@ -81,7 +81,10 @@ void AppGetSettings(CefSettings& settings, CefRefPtr app) { { std::string str = g_command_line->GetSwitchValue(cefclient::kLogSeverity); - bool invalid = false; + + // Default to LOGSEVERITY_DISABLE + settings.log_severity = LOGSEVERITY_DISABLE; + if (!str.empty()) { if (str == cefclient::kLogSeverity_Verbose) settings.log_severity = LOGSEVERITY_VERBOSE; @@ -95,14 +98,6 @@ void AppGetSettings(CefSettings& settings, CefRefPtr app) { settings.log_severity = LOGSEVERITY_ERROR_REPORT; else if (str == cefclient::kLogSeverity_Disable) settings.log_severity = LOGSEVERITY_DISABLE; - else - invalid = true; - } - if (str.empty() || invalid) { -#ifdef NDEBUG - // Only log error messages and higher in release build. - settings.log_severity = LOGSEVERITY_ERROR; -#endif } } diff --git a/appshell/cefclient.rc b/appshell/cefclient.rc index 501521f14..b88268fb0 100644 --- a/appshell/cefclient.rc +++ b/appshell/cefclient.rc @@ -29,7 +29,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO -FILEVERSION 0,13,0,0 +FILEVERSION 0,14,0,0 /* PRODUCTVERSION 1,0,0,0 */ FILEOS VOS__WINDOWS32 FILETYPE VFT_APP @@ -40,7 +40,7 @@ BEGIN BEGIN VALUE "CompanyName", "brackets.io\0" VALUE "FileDescription", "\0" - VALUE "FileVersion", "Sprint 13\0" + VALUE "FileVersion", "Sprint 14\0" VALUE "ProductName", "Brackets\0" VALUE "ProductVersion", "\0" VALUE "LegalCopyright", "(c) 2012 Adobe Systems, Inc.\0" @@ -88,10 +88,6 @@ BEGIN BEGIN MENUITEM "E&xit", IDM_EXIT END - POPUP "&Help" - BEGIN - MENUITEM "&About", IDM_ABOUT - END END IDC_CEFCLIENT_POPUP MENU @@ -100,10 +96,6 @@ BEGIN BEGIN MENUITEM "&Close", IDM_CLOSE END - POPUP "&Help" - BEGIN - MENUITEM "&About", IDM_ABOUT - END END IDC_CEFCLIENT_FR MENU @@ -112,10 +104,6 @@ BEGIN BEGIN MENUITEM "&Quitter", IDM_EXIT END - POPUP "&Aide" - BEGIN - MENUITEM "&A propos", IDM_ABOUT - END END IDC_CEFCLIENT_POPUP_FR MENU @@ -124,10 +112,6 @@ BEGIN BEGIN MENUITEM "&Fermer", IDM_CLOSE END - POPUP "&Aide" - BEGIN - MENUITEM "&A propos", IDM_ABOUT - END END ///////////////////////////////////////////////////////////////////////////// @@ -194,7 +178,7 @@ END STRINGTABLE BEGIN - IDS_APP_TITLE "cefclient" + IDS_APP_TITLE "Brackets" IDC_CEFCLIENT "CEFCLIENT" END diff --git a/appshell/cefclient_mac.mm b/appshell/cefclient_mac.mm index e98716227..09559853e 100644 --- a/appshell/cefclient_mac.mm +++ b/appshell/cefclient_mac.mm @@ -3,7 +3,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "config.h" #import #include #include "cefclient.h" @@ -15,6 +14,7 @@ #include "client_handler.h" #include "resource_util.h" #include "string_util.h" +#include "config.h" #include "appshell_extensions.h" #include "command_callbacks.h" @@ -286,7 +286,7 @@ - (void)createApp:(id)object { NSResizableWindowMask ) backing:NSBackingStoreBuffered defer:NO]; - [mainWnd setTitle:@"Brackets"]; + [mainWnd setTitle:APP_NAME]; [mainWnd setDelegate:delegate]; [mainWnd setCollectionBehavior: (1 << 7) /* NSWindowCollectionBehaviorFullScreenPrimary */]; @@ -441,22 +441,21 @@ int main(int argc, char* argv[]) { CGEventRef event = CGEventCreate(NULL); CGEventFlags modifiers = CGEventGetFlags(event); CFRelease(event); - - // If the Option key is down, delete any saved preferences - if ((modifiers & kCGEventFlagMaskAlternate) == kCGEventFlagMaskAlternate) { - [[NSUserDefaults standardUserDefaults] setURL:nil forKey:@"initialUrl"]; - } - // If the shift key is down, always let the user select the startup file + // If the shift key is not pressed, look for index.html bundled in the app package if ((modifiers & kCGEventFlagMaskShift) != kCGEventFlagMaskShift) { - startupUrl = [[NSUserDefaults standardUserDefaults] URLForKey:@"initialUrl"]; + NSString* bundlePath = [[NSBundle mainBundle] bundlePath]; + + // First, look in our app package for /Contents/dev/src/index.html + NSString* devFile = [bundlePath stringByAppendingString:@"/Contents/dev/src/index.html"]; + + if ([[NSFileManager defaultManager] fileExistsAtPath:devFile]) { + startupUrl = [NSURL fileURLWithPath:devFile]; + } - // If we don't have a startup url saved in preferences, check for an index.html - // file in the www directory in our app package. if (startupUrl == nil) { - NSString* bundlePath = [[NSBundle mainBundle] bundlePath]; + // If the dev file wasn't found, look for /Contents/www/index.html NSString* indexFile = [bundlePath stringByAppendingString:@"/Contents/www/index.html"]; - if ([[NSFileManager defaultManager] fileExistsAtPath:indexFile]) { startupUrl = [NSURL fileURLWithPath:indexFile]; } @@ -464,11 +463,12 @@ int main(int argc, char* argv[]) { } if (startupUrl == nil) { + // If we got here, either the startup file couldn't be found, or the user pressed the + // shift key while launching. Prompt to select the index.html file. NSOpenPanel* openPanel = [NSOpenPanel openPanel]; - [openPanel setTitle:@"Please select the brackets index.html file"]; + [openPanel setTitle:[NSString stringWithFormat:@"Please select the %@ index.html file", APP_NAME]]; if ([openPanel runModal] == NSOKButton) { - startupUrl = [NSURL fileURLWithPath:[[openPanel filenames] objectAtIndex:0]]; - [[NSUserDefaults standardUserDefaults] setURL:startupUrl forKey:@"initialUrl"]; + startupUrl = [[openPanel URLs] objectAtIndex:0]; } else { // User chose cancel when selecting startup file. Exit. @@ -506,7 +506,7 @@ int main(int argc, char* argv[]) { CefString AppGetCachePath() { // Set persistence cache NSString *libraryDirectory = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0]; - NSString *cefCacheDirectory = [NSString stringWithFormat:@"%@/Brackets/cef_data", libraryDirectory]; + NSString *cefCacheDirectory = [NSString stringWithFormat:@"%@/%@%@/cef_data", libraryDirectory, GROUP_NAME, APP_NAME]; CefString cachePath = [cefCacheDirectory UTF8String]; return cachePath; diff --git a/appshell/cefclient_win.cpp b/appshell/cefclient_win.cpp index 0e8e06502..e53e9178f 100644 --- a/appshell/cefclient_win.cpp +++ b/appshell/cefclient_win.cpp @@ -2,7 +2,6 @@ // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. -#include "config.h" #include "cefclient.h" #include #include @@ -16,6 +15,7 @@ #include "include/cef_frame.h" #include "include/cef_runnable.h" #include "client_handler.h" +#include "config.h" #include "resource.h" #include "string_util.h" @@ -99,37 +99,31 @@ int APIENTRY wWinMain(HINSTANCE hInstance, LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_CEFCLIENT, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance, settings.locale); - - HKEY hKey; - DWORD lResult; - #define PREF_NAME L"Software\\Brackets\\InitialURL" - - // If the Control key is down, delete the prefs - BOOL bDeletePrefs = false; - if (GetAsyncKeyState(VK_CONTROL) != 0) { - bDeletePrefs = true; - } + - // Don't read the prefs if the shift key is down + // If the shift key is not pressed, look for the index.html file if (GetAsyncKeyState(VK_SHIFT) == 0) { - if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, PREF_NAME, 0, KEY_READ, &hKey)) { - if (bDeletePrefs) { - RegDeleteKey(hKey, L""); - } else { - DWORD length = MAX_PATH; - RegQueryValueEx(hKey, NULL, NULL, NULL, (LPBYTE)szInitialUrl, &length); - RegCloseKey(hKey); - } + // Get the full pathname for the app. We look for the index.html + // file relative to this location. + wchar_t appPath[MAX_PATH]; + wchar_t *pathRoot; + GetModuleFileName(NULL, appPath, MAX_PATH); + + // Strip the .exe filename (and preceding "\") from the appPath + // and store in pathRoot + pathRoot = wcsrchr(appPath, '\\'); + + // Look for .\dev\src\index.html first + wcscpy(pathRoot, L"\\dev\\src\\index.html"); + + // If the file exists, use it + if (GetFileAttributes(appPath) != INVALID_FILE_ATTRIBUTES) { + wcscpy(szInitialUrl, appPath); } if (!wcslen(szInitialUrl)) { - // Look for www/index.html in the same directory as the application - wchar_t appPath[MAX_PATH]; - GetModuleFileName(NULL, appPath, MAX_PATH); - - wcscpy(wcsrchr(appPath, '\\'), L"\\www\\index.html"); - - // If the file exists, use it + // Look for .\www\index.html next + wcscpy(pathRoot, L"\\www\\index.html"); if (GetFileAttributes(appPath) != INVALID_FILE_ATTRIBUTES) { wcscpy(szInitialUrl, appPath); } @@ -137,21 +131,17 @@ int APIENTRY wWinMain(HINSTANCE hInstance, } if (!wcslen(szInitialUrl)) { + // If we got here, either the startup file couldn't be found, or the user pressed the + // shift key while launching. Prompt to select the index.html file. OPENFILENAME ofn = {0}; ofn.lStructSize = sizeof(ofn); ofn.lpstrFile = szInitialUrl; ofn.nMaxFile = MAX_PATH; ofn.lpstrFilter = L"Web Files\0*.htm;*.html\0\0"; - ofn.lpstrTitle = L"Please select the brackets index.html file."; + ofn.lpstrTitle = L"Please select the " APP_NAME L" index.html file."; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_EXPLORER; - if (GetOpenFileName(&ofn)) { - lResult = RegCreateKeyEx(HKEY_CURRENT_USER, PREF_NAME, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL); - if (lResult == ERROR_SUCCESS) { - RegSetValueEx(hKey, NULL, 0, REG_SZ, (LPBYTE)szInitialUrl, (wcslen(szInitialUrl) + 1) * 2); - RegCloseKey(hKey); - } - } else { + if (!GetOpenFileName(&ofn)) { // User cancelled, exit the app CefShutdown(); return 0; @@ -403,11 +393,6 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { - case IDM_ABOUT: - if (browser) { - g_handler->SendJSCommand(browser, HELP_ABOUT); - } - return 0; case IDM_EXIT: if (g_handler.get()) { g_handler->QuittingApp(true); @@ -578,7 +563,7 @@ CefString AppGetCachePath() { SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, dataPath); std::wstring cachePath = dataPath; - cachePath += L"\\Brackets\\cef_data"; + cachePath += L"\\" GROUP_NAME APP_NAME L"\\cef_data"; return CefString(cachePath); } \ No newline at end of file diff --git a/appshell/client_app_mac.mm b/appshell/client_app_mac.mm index 8f2c2450b..a7de67558 100644 --- a/appshell/client_app_mac.mm +++ b/appshell/client_app_mac.mm @@ -49,6 +49,18 @@ // NSLog(@"%@", language); NSString* language = [[NSLocale preferredLanguages] objectAtIndex:0]; + + // Remap zh-Hans --> zh-CN and zh-Hant --> zh-TW so that CEF3 can find the corresponding localized resources. + // We may need to remove these two lines in the future if CEF3 switches to the newer locale names. + language = [language stringByReplacingOccurrencesOfString:@"Hans" withString:@"CN"]; + language = [language stringByReplacingOccurrencesOfString:@"Hant" withString:@"TW"]; + + // Remap pt --> pt-BR so that we can load the CEF3 resource for Brazilian Portuguese. + // [rlim] I believe this is the last one that we have to remap. If we find any to reamp again, + // then we should just switch to CFLocaleCopyPreferredLanguages() instead of [[NSLocale preferredLanguages]. + if ([language isEqualToString:@"pt"]) + language = [language stringByReplacingOccurrencesOfString:@"pt" withString:@"pt-BR"]; + CefString result = [language UTF8String]; return result; } diff --git a/appshell/client_handler.cpp b/appshell/client_handler.cpp index 433a1a2f5..870d570a1 100644 --- a/appshell/client_handler.cpp +++ b/appshell/client_handler.cpp @@ -321,7 +321,7 @@ void ClientHandler::ShowDevTools(CefRefPtr browser) { } } -void ClientHandler::SendJSCommand(CefRefPtr browser, const CefString& commandName, CefRefPtr callback) +bool ClientHandler::SendJSCommand(CefRefPtr browser, const CefString& commandName, CefRefPtr callback) { CefRefPtr message = CefProcessMessage::Create("executeCommand"); message->GetArgumentList()->SetString(0, commandName); @@ -332,30 +332,44 @@ void ClientHandler::SendJSCommand(CefRefPtr browser, const CefString message->GetArgumentList()->SetInt(1, callbackId); } - browser->SendProcessMessage(PID_RENDERER, message); + return browser->SendProcessMessage(PID_RENDERER, message); } -void ClientHandler::DispatchCloseToNextBrowser() { - // Close the first (main) window last. On Windows, closing the main window exits the application, - // so make sure all other windows get a crack at saving changes first. - bool skipFirstOne = (browser_window_map_.size() > 1); - for (BrowserWindowMap::const_iterator i = browser_window_map_.begin(); - i != browser_window_map_.end(); i++) { - if (skipFirstOne) { +void ClientHandler::DispatchCloseToNextBrowser() +{ + // If the inner loop iterates thru all browsers and there's still at least one + // left (i.e. the first browser that was skipped), then re-start loop + while (browser_window_map_.size() > 0) + { + // Close the first (main) window last. On Windows, closing the main window exits the + // application, so make sure all other windows get a crack at saving changes first. + bool skipFirstOne = (browser_window_map_.size() > 1); + + BrowserWindowMap::const_iterator i; + for (i = browser_window_map_.begin(); i != browser_window_map_.end(); i++) + { + if (skipFirstOne) { skipFirstOne = false; continue; - } - CefRefPtr browser = i->second; + } + CefRefPtr browser = i->second; - // Bring the window to the front before sending the command - BringBrowserWindowToFront(browser); + // Bring the window to the front before sending the command + BringBrowserWindowToFront(browser); - // This call initiates a quit sequence. We will continue to close browser windows - // unless AbortQuit() is called. - m_quitting = true; - CefRefPtr callback = new CloseWindowCommandCallback(browser); - SendJSCommand(browser, FILE_CLOSE_WINDOW, callback); - return; + // This call initiates a quit sequence. We will continue to close browser windows + // unless AbortQuit() is called. + m_quitting = true; + CefRefPtr callback = new CloseWindowCommandCallback(browser); + + if (SendJSCommand(browser, FILE_CLOSE_WINDOW, callback)) { + // JS Command successfully sent, so we're done + return; + } + + // Sending JS command to browser failed, so remove it from queue, continue to next browser + browser_window_map_.erase(i->first); + } } } diff --git a/appshell/client_handler.h b/appshell/client_handler.h index aeedf90f6..c7c097a82 100644 --- a/appshell/client_handler.h +++ b/appshell/client_handler.h @@ -183,7 +183,7 @@ class ClientHandler : public CefClient, // Call the "executeCommand" method, passing the command name. // If callback is specified, it will be called with the result from the command. - void SendJSCommand(CefRefPtr browser, const CefString& command, CefRefPtr callback = NULL); + bool SendJSCommand(CefRefPtr browser, const CefString& command, CefRefPtr callback = NULL); void DispatchCloseToNextBrowser(); void AbortQuit(); diff --git a/appshell/client_handler_win.cpp b/appshell/client_handler_win.cpp index a29286dd5..a112dc40e 100644 --- a/appshell/client_handler_win.cpp +++ b/appshell/client_handler_win.cpp @@ -118,11 +118,6 @@ LRESULT CALLBACK PopupWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPa // Parse the menu selections: switch (wmId) { - case IDM_ABOUT: - if (browser.get()) { - g_handler->SendJSCommand(browser, HELP_ABOUT); - } - return 0; case IDM_CLOSE: if (g_handler.get() && browser.get()) { HWND browserHwnd = browser->GetHost()->GetWindowHandle(); diff --git a/appshell/config.h b/appshell/config.h index 7d5250cc3..9512d5234 100644 --- a/appshell/config.h +++ b/appshell/config.h @@ -1,2 +1,44 @@ +/* + * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#pragma once + +// Application name used in native code. This name is *not* used in resources. + +#ifdef OS_WIN +// Name of group (if any) that application prefs/settings/etc. are stored under +// This must be an empty string (for no group), or a string that ends with "\\" +#define GROUP_NAME L"" +#define APP_NAME L"Brackets" +#endif +#ifdef OS_MACOSX +// Name of group (if any) that application prefs/settings/etc. are stored under +// This must be an empty string (for no group), or a string that ends with "/" +#define GROUP_NAME @"" +#define APP_NAME @"Brackets" +#endif + + +// Un-comment this line to show the toolbar UI at the top of the appshell window // #define SHOW_TOOLBAR_UI diff --git a/installer/mac/README.MD b/installer/mac/README.MD index 04026eb46..590e369a1 100644 --- a/installer/mac/README.MD +++ b/installer/mac/README.MD @@ -1,20 +1,31 @@ ## Overview -This readme describes how the .dmg file is created for Brackets on Mac. Like many Mac apps Brackets doesn't have an installer. Instead the user opens a disk image file (.dmg) and manually drags Brackets.app to their Applications folder. +This readme describes how the .dmg file is created for Brackets on Mac. Like many Mac apps +Brackets doesn't have an installer. Instead the user opens a disk image file (.dmg) and manually +drags Brackets.app to their Applications folder. ## To create a Brackets dmg -1) Install DropDMG (http://c-command.com/dropdmg/) -2) Set up the payload for the dmg by copying Brackets.app to brackets-shell\installer\mac\staging\ - Note, scripts and instructions for how to build Brackets.app for a dmg image are coming soon. -3) Open brackets-shell\installer\mac\buildInstaller.sh in a text editor and update "releaseName" variable at the top of the file -4) Execute the script buildInstaller.sh from brackets-shell\installer\mac\ - A new dmg file will be created at brackets-shell\installer\mac\ - +1. Install DropDMG (http://c-command.com/dropdmg/) and Xcode 4.x. If the command-line Xcode build + tools are not automatically installed, download them from the Apple Developer Center. +2. Run DropDMG once. In Preferences > Advanced, click "Install 'dropdmg' Tool". +3. In Terminal, do: `export BRACKETS_SRC=` +4. From the root of brackets-shell, do: `./scripts/build_mac.sh`. This will place the DMG in + the installer/mac folder. + +Note that after this process, you will be on the master branch in both the brackets-shell +and brackets repos. ## How it Works -- DropDMG provides both a GUI and command line interface for building Mac dmg files. See http://c-command.com/dropdmg/. Brackets uses the shell script interface to control DropDMG. Using the command line instead of the GUI allows build settings to be stored as text and tracked in the brackets-shell git repo. - -- buildInstaller.sh sets up some configuration variables regarding the name of the release, creates a temporary directory for the build and then makes a single call to dropdmg to create the dmg. All the options used to build the disk image are specified via command arguments except the layout for the disk image. The layout is described via the brackets-shell\installer\mac\dropDmgConfig\layouts\bracketsLayout folder. This folder contains an Info.plist file, icons, and background image that DropDMG uses to layout the appearance of the disk image. This layout folder is generated by the DropDMG GUI tool. Dragging a layout from DropDMG to the tool creates this folder structure. +* DropDMG provides both a GUI and command line interface for building Mac dmg files. + See http://c-command.com/dropdmg/. Brackets uses the shell script interface to control + DropDMG. Using the command line instead of the GUI allows build settings to be stored as + text and tracked in the brackets-shell git repo. -## Issues -The Info.plist references file names using a name and a hash and specifies their icon location. Since Brackets updates the app name with each sprint, the Info.plist needs to handle each sprint name. Since it's currently not known how to templatize the Info.plist for DropDMG the current Info.plist file has sprints 13-20 already specified so layouts will work correctly up to sprint 20. \ No newline at end of file +- buildInstaller.sh sets up some configuration variables regarding the name of the release, + creates a temporary directory for the build and then makes a single call to dropdmg to + create the dmg. All the options used to build the disk image are specified via command + arguments except the layout for the disk image. The layout is described via the + brackets-shell\installer\mac\dropDmgConfig\layouts\bracketsLayout folder. This folder + contains an Info.plist file, icons, and background image that DropDMG uses to layout the + appearance of the disk image. This layout folder is generated by the DropDMG GUI tool. + Dragging a layout from DropDMG to the tool creates this folder structure. diff --git a/installer/mac/buildInstaller.sh b/installer/mac/buildInstaller.sh index 350a2da17..fb494af10 100755 --- a/installer/mac/buildInstaller.sh +++ b/installer/mac/buildInstaller.sh @@ -1,29 +1,44 @@ #!/bin/bash # config -releaseName="Brackets Sprint 13" +releaseName="Brackets Sprint 14" format="bzip2" encryption="none" tmpLayout="./dropDmgConfig/layouts/tempLayout" -appName=$releaseName".app" +appName="${releaseName}.app" tempDir="tempBuild" # rename app and copy to tempBuild director rm -rf $tempDir mkdir $tempDir -cp -r ./staging/Brackets.app/ "$tempDir/$appName" +cp -r "./staging/${BRACKETS_APP_NAME}.app/" "$tempDir/$appName" + +# create symlink to Applications folder in staging area +# with a single space as the name so it doesn't show an unlocalized name +ln -s /Applications "$tempDir/ " + +# copy volume icon to staging area if one exists +customIcon="" +if [ -f ./assets/VolumeIcon.icns ]; then + cp ./assets/VolumeIcon.icns "$tempDir/.VolumeIcon.icns" + customIcon="--custom-icon" +fi + +# if license folder exists, use it +if [ -d ./dropDmgConfig/licenses/bracketsLicense ]; then + customLicense="--license-folder ./dropDmgConfig/licenses/bracketsLicense" +fi # create disk layout rm -rf $tempLayoutDir -cp -r ./dropDmgConfig/layouts/bracketsLayout/ $tmpLayout +cp -r ./dropDmgConfig/layouts/bracketsLayout/ "$tmpLayout" # Replace APPLICATION_NAME in Info.plist with $releaseName.app -grep -rl APPLICATION_NAME $tmpLayout/Info.plist | xargs sed -i -e "s/APPLICATION_NAME/$releaseName.app/g" - +grep -rl APPLICATION_NAME "${tmpLayout}/Info.plist" | xargs sed -i -e "s/APPLICATION_NAME/${releaseName}.app/g" # build the DMG echo "building DMG..." -dropdmg ./$tempDir --format $format --encryption $encryption --layout-folder $tmpLayout --volume-name "$releaseName" --base-name "$releaseName" +dropdmg ./$tempDir --format $format --encryption $encryption $customIcon --layout-folder "$tmpLayout" $customLicense --volume-name "$releaseName" --base-name "$releaseName" # clean up rm -rf $tempDir diff --git a/installer/mac/dropDmgConfig/layouts/bracketsLayout/Info.plist b/installer/mac/dropDmgConfig/layouts/bracketsLayout/Info.plist index 113cd66ea..2c1803200 100644 --- a/installer/mac/dropDmgConfig/layouts/bracketsLayout/Info.plist +++ b/installer/mac/dropDmgConfig/layouts/bracketsLayout/Info.plist @@ -20,11 +20,11 @@ identifier LayoutItem.41ACEC13-5995-48E6-A3F1-6C766090B2BF name - Applications + position {327, 148} type - applications + identifier diff --git a/installer/win/Brackets.wxs b/installer/win/Brackets.wxs index 21ee987b3..ecb4486fe 100644 --- a/installer/win/Brackets.wxs +++ b/installer/win/Brackets.wxs @@ -3,13 +3,19 @@ + - + - @@ -17,8 +23,8 @@ xmlns:fire="http://schemas.microsoft.com/wix/FirewallExtension"> - - + + @@ -27,11 +33,11 @@ xmlns:fire="http://schemas.microsoft.com/wix/FirewallExtension"> - - + @@ -42,36 +48,26 @@ xmlns:fire="http://schemas.microsoft.com/wix/FirewallExtension"> - + 1 - LAUNCHAPPONEXIT=1 and NOT INSTALLED AND NOT REMOVE="ALL" + - - - - - - - - - + - - - - + + diff --git a/installer/win/Brackets_en-us.wxl b/installer/win/Brackets_en-us.wxl index 15734c659..e983bf8f8 100644 --- a/installer/win/Brackets_en-us.wxl +++ b/installer/win/Brackets_en-us.wxl @@ -10,11 +10,48 @@ You must not remove this notice, or any other, from this software. --> + EULA_en-us.rtf - {\WixUI_Font_Title}Remove installation - Shortcut to Brackets - Launch Brackets when setup exits. - {\WixUI_Font_Title}[ProductName] Setup Wizard was interrupted - {\WixUI_Font_Title}Completed the [ProductName] Setup Wizard + + + Brackets + Brackets + + 1033 + + [ProductName] Installer + [ProductName] Installer + + {\WixUI_Font_BannerTitle}!(loc.ShortProductName) Destination Folder + {\WixUI_Font_BannerTitle}Change !(loc.ShortProductName) Destination Folder + {\WixUI_Font_BannerTitle}Install !(loc.ShortProductName) + + {\WixUI_Font_BannerTitle}Installing !(loc.ShortProductName) + Please wait while !(loc.ShortProductName) is installed. + {\WixUI_Font_BannerTitle}Uninstalling !(loc.ShortProductName) + Please wait while !(loc.ShortProductName) is uninstalled. + + Progress: + + {\WixUI_Font_BannerTitle}!(loc.ShortProductName) was successfully installed. + {\WixUI_Font_BannerTitle}!(loc.ShortProductName) was successfully uninstalled. + + Installation was interrupted. Your system has not been modified. + + Click Finish to exit. + {\WixUI_Font_BannerTitle}Uninstall !(loc.ShortProductName) + + Remove installation + This application is only supported on Windows Vista, Windows Server 2008, or higher. + For automated device pairing, we recommend you install Bonjour, which is in the !(loc.ShortProductName) folder at [INSTALLDIR]BonjourPSSetup.exe. + Check the Install Guide for further instructions on installing the Chrome Extension. + Shortcut to !(loc.ShortProductName) + Start !(loc.ShortProductName) when the Installer exits. + {\WixUI_Font_BannerTitle}!(loc.ShortProductName) installation was interrupted + {\WixUI_Font_BannerTitle}Completed the [ProductName] Setup Wizard + Click Install to begin, or Cancel to exit. + Click Remove to uninstall !(loc.ShortProductName), or Cancel to exit. \ No newline at end of file diff --git a/installer/win/Brackets_fr-fr.wxl b/installer/win/Brackets_fr-fr.wxl index 2f060f7a5..1b96e58af 100644 --- a/installer/win/Brackets_fr-fr.wxl +++ b/installer/win/Brackets_fr-fr.wxl @@ -10,15 +10,276 @@ You must not remove this notice, or any other, from this software. --> + EULA_fr-fr.rtf - {\WixUI_Font_Title}Supprimer le logiciel installé + Brackets + Brackets + + 1036 + + Programme d’installation de [ProductName] + Programme d’installation de [ProductName] + + {\WixUI_Font_BannerTitle}Dossier de destination pour !(loc.ShortProductName) + {\WixUI_Font_BannerTitle}Changement de dossier de destination pour !(loc.ShortProductName) + {\WixUI_Font_BannerTitle}Installer !(loc.ShortProductName) + + {\WixUI_Font_BannerTitle}Installation de !(loc.ShortProductName) + Veuillez patienter pendant l’installation de !(loc.ShortProductName). + {\WixUI_Font_BannerTitle}Désinstallation de !(loc.ShortProductName) + Veuillez patienter pendant la désinstallation de !(loc.ShortProductName). + + Progression : + + {\WixUI_Font_BannerTitle}Installation de !(loc.ShortProductName) terminée + {\WixUI_Font_BannerTitle}Désinstallation de !(loc.ShortProductName) terminée + + Procédure d’installation interrompue. Votre système n’a pas été modifié. + + Cliquez sur Terminer pour quitter. + {\WixUI_Font_BannerTitle}Désinstaller !(loc.ShortProductName) + + Supprimer l’installation Cette application n’est prise en charge que sous Windows Vista, Windows Server 2008 et versions ultérieures. - REMARQUE : l’application Bonjour est introuvable sur cet ordinateur. Reportez-vous au guide d’installation pour savoir comment installer ce logiciel. + Pour le couplage automatisé de périphériques, nous vous recommandons d’installer l’application Bonjour, qui se trouve dans le dossier !(loc.ShortProductName) sous [INSTALLDIR]BonjourPSSetup.exe. Reportez-vous au guide d’installation pour savoir comment installer l’extension Chrome. - [Lo] !é=Shortcut to Brackets=! - [Ll] !é=Launch Brackets when setup exits.=! - [Ly] !é=[ProductName] Setup Wizard was interrupted=! - [Lx] !é=Completed the [ProductName] Setup Wizard=! + Raccourci vers !(loc.ShortProductName) + Lancer !(loc.ShortProductName) à la fin de l’installation + {\WixUI_Font_BannerTitle}Procédure d’installation de !(loc.ShortProductName) interrompue + {\WixUI_Font_BannerTitle}Procédure de l’assistant d’installation de [ProductName] terminée + Cliquez sur Installer pour lancer la procédure ou sur Annuler pour quitter. + Cliquez sur Supprimer pour désinstaller !(loc.ShortProductName) ou sur Annuler pour quitter. + + + + &Imprimer + J’&accepte les termes de ce contrat de licence + Cliquez sur Installer pour installer les options par défaut pour tous les utilisateurs. Cliquez sur Avancé pour modifier les options d’installation. + Cliquez sur Installer pour installer les options par défaut pour votre compte uniquement. Cliquez sur Avancé pour modifier les options d’installation. + &Consulter : + Voulez-vous vraiment annuler l’installation de [ProductName] ? + Icône d’information + Cliquez sur les icônes dans l’arborescence ci-dessous pour modifier la manière dont les nouvelles fonctionnalités seront installées. + Sélectionnez la manière dont vous souhaitez installer les fonctionnalités. + Les volumes en surbrillance ne disposent pas de l’espace disque disponible pour les fonctionnalités sélectionnées. Vous pouvez supprimer certains fichiers des volumes en surbrillance, installer moins d’options ou choisir une autre destination. + Espace disque requis pour l’installation des fonctionnalités sélectionnées. + Texte d’information + Icône d’information + Cliquez sur le bouton Terminer pour quitter l’installation. + {\WixUI_Font_Bigger}L’installation de [ProductName] s’est terminée avant sa fin. + A la suite d’une erreur, l’installation de [ProductName] s’est terminée avant sa fin. Votre système n’a pas été modifié. Pour installer ce programme ultérieurement, réexécutez le programme d’installation. + Cliquez sur le bouton Terminer pour quitter l’installation. + Les programmes suivants utilisent des fichiers que le programme d’installation doit mettre à jour. Fermez les programmes répertoriés, puis cliquez sur &Réessayer pour poursuivre l’installation ou cliquez sur Quitter pour l’annuler. + Plusieurs fichiers devant être mis à jour sont en cours d’utilisation. + {\WixUI_Font_Title}Fichiers en cours d’utilisation + Cliquez sur Suivant pour procéder à l’installation dans le dossier par défaut ou sur Modifier pour choisir une autre destination. + Choisissez le type d’installation ainsi que le dossier de destination. + {\WixUI_Font_Title}Type d’installation + {\WixUI_Font_Emphasized}Installer &pour votre compte utilisateur uniquement ([USERNAME]) + [ProductName] ne sera disponible que pour votre compte utilisateur. Vous ne devez pas disposer des privilèges d’administrateur local. + [ProductName] ne prend pas en charge l’installation par utilisateur. + [ProductName] sera installé dans un dossier par utilisateur par défaut et sera disponible pour tous les utilisateurs. Vous pouvez modifier le dossier de destination. Vous devez disposer des privilèges d’administrateur local. + &Dossier d’installation : + Le répertoire d’installation doit se situer sur un disque dur local. + Icône d’information + J’&accepte les termes de ce contrat de licence + Modifier l’installation + Réparer l’installation + Supprimer l’installation + Sélectionnez l’opération que vous souhaitez effectuer. + {\WixUI_Font_Title}Modifier, réparer ou supprimer l’installation + Supprime [ProductName] de votre ordinateur. + [ProductName] ne peut pas être supprimé. + Répare les erreurs de l’installation la plus récente en intervenant sur les fichiers manquants et corrompus, les raccourcis et les entrées de la base de registres. + [ProductName] ne peut pas être réparé. + Le programme d’installation vous permet de modifier la manière dont les fonctionnalités de [ProductName] sont installées sur votre ordinateur ou de supprimer le programme de votre ordinateur. Cliquez sur Suivant pour continuer ou sur Annuler pour quitter le programme d’installation. + {\WixUI_Font_Bigger}Bienvenue dans le programme d’installation de [ProductName]. + Vous pouvez laisser le programme d’installation les fermer et tenter de les redémarrer, ou redémarrer la machine ultérieurement. + Plusieurs fichiers devant être mis à jour sont en cours d’utilisation. + {\WixUI_Font_Title}Fichiers en cours d’utilisation + &Ne fermez pas les programmes. Vous devez redémarrer l’ordinateur une fois l’installation terminée. + Les volumes en surbrillance ne disposent pas de suffisamment d’espace disque pour les fonctionnalités sélectionnées. Vous pouvez supprimer certains fichiers des volumes en surbrillance, installer moins d’options ou choisir une autre destination. + L’espace disque disponible est insuffisant pour l’installation. + Les volumes en surbrillance ne disposent pas de suffisamment d’espace disque pour les fonctionnalités sélectionnées. Vous pouvez supprimer certains fichiers des volumes en surbrillance, installer moins d’options ou choisir une autre destination. + L’espace disque disponible est insuffisant pour l’installation. + Vous pouvez choisir de désactiver la fonction de restauration du programme d’installation. Ce faisant, l’état d’origine de l’ordinateur n’est pas restauré si l’installation est interrompue. Cliquez sur Oui pour désactiver la restauration. + Veuillez patienter pendant que le programme d’installation se prépare à vous guider dans l’installation. + {\WixUI_Font_Bigger}Bienvenue dans le programme d’installation de [ProductName]. + Veuillez patienter pendant que le programme d’installation installe [ProductName]. + Veuillez patienter pendant que le programme d’installation modifie [ProductName]. + Veuillez patienter pendant que le programme d’installation répare [ProductName]. + Veuillez patienter pendant que le programme d’installation supprime [ProductName]. + Le programme d’installation va installer [ProductName] sur votre ordinateur. Cliquez sur Installer pour continuer ou sur Annuler pour quitter le programme d’installation. + {\WixUI_Font_Bigger}Reprise de l’installation de [ProductName]. + P&ersonnalisé + Terminé + Installation terminée + {\WixUI_Font_Title}Choix du type d’installation + Choisissez le type d’installation le mieux adapté à vos besoins. + Vous permet de choisir les fonctionnalités à installer ainsi que leur emplacement. Recommandé uniquement pour les utilisateurs avancés. + {\WixUI_Font_Bigger}L’installation de [ProductName] a été interrompue. + L’installation de [ProductName] a été interrompue. Votre système n’a pas été modifié. Pour installer ce programme ultérieurement, réexécutez le programme d’installation. + Cliquez sur le bouton Terminer pour quitter l’installation. + Cliquez sur Installer pour commencer. Cliquez sur Retour pour revoir ou modifier les paramètres d’installation. Cliquez sur Annuler pour quitter le programme d’installation. + Cliquez sur Modifier pour commencer. Cliquez sur Retour pour revoir ou modifier les paramètres d’installation. Cliquez sur Annuler pour quitter le programme d’installation. + Cliquez sur Réparer pour réparer [ProductName]. Cliquez sur Retour pour revoir ou modifier les paramètres d’installation. Cliquez sur Annuler pour quitter le programme d’installation. + Cliquez sur Supprimer pour supprimer [ProductName]. Cliquez sur Retour pour revoir ou modifier les paramètres d’installation. Cliquez sur Annuler pour quitter le programme d’installation. + Revenir + Veuillez patienter pendant que le programme d’installation détermine l’espace disque requis. + Icône d’exclamation + Le programme d’installation va installer [ProductName] sur votre ordinateur. Cliquez sur Suivant pour continuer ou sur Annuler pour quitter le programme d’installation. + {\WixUI_Font_Bigger}Bienvenue dans le programme d’installation de [ProductName]. + J’&accepte les termes de ce contrat de licence + Validation de l’installation + Copie des fichiers d’installation réseau + Calcul de l’espace requis + Calcul de l’espace requis + Calcul de l’espace requis + Enregistrement des serveurs de classes + Enregistrement des serveurs d’extension + Enregistrement des informations MIME + Enregistrement des identificateurs de programme + Allocation d’espace dans le Registre + Evaluation des conditions de lancement + Mise à jour de l’enregistrement des composants + Enregistrement des applications et des composants COM + + ID d’application : [1]{{, type d’application : [2], utilisateur : [3], RSN : [4]}} + Enregistrement des polices + Enregistrement du produit + Enregistrement des bibliothèques de types + Enregistrement de l’utilisateur + Mise à jour des chaînes d’environnement + Suppression des applications + Enregistrement des modules + Annulation de l’enregistrement des modules + Annulation de l’enregistrement des serveurs de classes + Annulation de l’enregistrement des applications et composants COM+ + ID de l’application : [1]{{, type d’application : [2]}} + Annulation de l’enregistrement des serveurs d’extension + Annulation de l’enregistrement des polices + Annulation de l’enregistrement des informations MIME + Annulation de l’enregistrement des identificateurs de programme + Annulation de l’enregistrement des bibliothèques de types + Mise à jour des chaînes d’environnement + Ecriture des valeurs des fichiers INI + Ecriture des valeurs de la base de registres + Publication d’informations sur l’application + Génération d’opérations de script pour l’action + Contexte de l’application :[1], nom du module :[2] + Contexte de l’application :[1], nom du module :[2] + Annulation de l’action: + Le programme d’installation a rencontré une erreur inattendue. Cela peut indiquer un problème lié à ce package. Le code d’erreur est : [1]. {{Les arguments sont : [2], [3], [4]}} + === Début de l’écriture dans le journal : [Date] [Time] === + === Fin de l’écriture dans le journal : [Date] [Time] === + Début de l’action [Time] : [1]. + Fin de l’action [Time] : [1]. Valeur de retour [2]. + Le programme d’installation ne répond plus. + Le programme d’installation s’est arrêté avant la fin de l’installation. + Echec de l’installation de {[ProductName]}. + Impossible de créer le fichier "[2]". Un répertoire du même nom existe déjà. Annulez l’installation et essayez d’installer à une autre destination. + Vous ne disposez pas des privilèges suffisants pour accéder à ce répertoire : [2]. Impossible de poursuivre l’installation. Ouvrez une session en tant qu’administrateur ou contactez votre administrateur système. + Erreur lors de l’écriture dans le fichier : [2]. Vérifiez que vous êtes autorisé à accéder à ce répertoire. + Le fichier "[2]" est ouvert en mode exclusif dans une autre application. Fermez tous les autres programmes, puis cliquez sur Réessayer. + Espace disque insuffisant pour installer le fichier : [2]. Libérez de l’espace disque et cliquez sur Réessayer, ou cliquez sur Annuler pour quitter. + Erreur lors de l’écriture dans le fichier : [3]. {{ Erreur système [2].}} Vérifiez que vous êtes autorisé à accéder à ce répertoire. + Impossible de créer le répertoire "[2]". Un fichier du même nom existe déjà. Renommez ou supprimez ce fichier et cliquez sur Réessayer, ou cliquez sur Annuler pour quitter. + Chemin d’accès spécifié "[2]" non disponible. + Impossible d’écrire vers le dossier spécifié : [2]. + Erreur au niveau du réseau lors de la tentative d’ouverture du fichier CAB source : [2] + Chemin d’accès spécifié trop long : [2] + Une partie du chemin d’accès au dossier "[2]" n’est pas valide. Il est vide ou dépasse la longueur maximale autorisée par le système. + Le chemin d’accès au dossier "[2]" contient des mots non valides. + Le chemin d’accès au dossier "[2]" contient un caractère non valide. + Le nom de fichier court "[2]" n’est pas valide. + Erreur lors de l’obtention des informations sur la sécurité du fichier : [3] GetLastError : [2] + Erreur de mise à jour du fichier [2]. Pour plus d’informations, contactez votre fournisseur. {{Erreur système : [3]}} + Un fichier requis ne peut pas être installé car le fichier CAB [2] n’est pas signé numériquement. Ceci peut indiquer qu’il est endommagé. + Un fichier requis ne peut pas être installé car la signature numérique du fichier CAB [2] n’est pas valide. Ceci peut indiquer qu’il est endommagé.{{ L’erreur [3] a été renvoyée par WinVerifyTrust.}} + Echec de la copie du fichier [2] : erreur CRC. + Echec du déplacement du fichier [2] : erreur CRC. + Echec de la mise à jour du fichier [2] : erreur CRC. + Le fichier "[2]" ne peut pas être installé car il ne se trouve pas dans le fichier CAB "[3]". Cela peut provenir d’une erreur de réseau ou d’une erreur de lecture du DVD. + Le fichier CAB "[2]" requis pour cette installation est endommagé et inutilisable. Cela peut provenir d’une erreur de réseau ou d’une erreur de lecture du DVD. + Erreur de création du fichier temporaire requis pour terminer cette installation.{{ Dossier : [3]. Code d’erreur système : [2]}} + Impossible de créer la clé [2]. {{ Erreur système [3].}} Vérifiez que vous disposez des droits d’accès nécessaires pour cette clé ou contactez votre service de support technique. + Impossible d’ouvrir la clé [2].{{ Erreur système [3].}} Vérifiez que vous disposez des droits d’accès nécessaires pour cette clé ou contactez votre service de support technique. + Impossible de supprimer la valeur [2] de la clé [3].{{ Erreur système [4].}} Vérifiez que vous disposez des droits d’accès nécessaires pour cette clé ou contactez votre service de support technique. + Impossible de supprimer la clé [2].{{ Erreur système [3].}} Vérifiez que vous disposez des droits d’accès nécessaires pour cette clé ou contactez votre service de support technique. + Impossible de lire la valeur [2] de la clé [3].{{ Erreur système [4].}} Vérifiez que vous disposez des droits d’accès nécessaires pour cette clé ou contactez votre service de support technique. + Impossible d’écrire la valeur [2] dans la clé [3].{{ Erreur système [4].}} Vérifiez que vous disposez des droits d’accès nécessaires pour cette clé ou contactez votre service de support technique. + Impossible d’obtenir le nom des valeurs de la clé [2].{{ Erreur système [3].}} Vérifiez que vous disposez des droits suffisants pour cette clé ou contactez votre service de support technique. + Impossible d’obtenir le nom des sous-clés de la clé [2].{{ Erreur système [3].}} Vérifiez que vous disposez des droits suffisants pour cette clé ou contactez votre service de support technique. + Impossible de lire les informations sur la sécurité de la clé [2].{{ Erreur système [3].}} Vérifiez que vous disposez des droits d’accès nécessaires pour cette clé ou contactez votre service de support technique + Impossible d’augmenter l’espace disponible dans le Registre. [2] Ko d’espace doivent être libres dans le Registre pour permettre l’installation de ce programme application. + Une autre installation est en cours d’exécution. Vous devez la terminer avant de poursuivre cette installation. + Erreur lors de l’accès aux données protégées. Vérifiez que Windows Installer est correctement configuré, puis recommencez l’installation. + L’utilisateur "[2]" a déjà lancé l’installation du produit "[3]". Il devra exécuter à nouveau cette installation avant de pouvoir utiliser le produit. Votre installation en cours va maintenant se poursuivre. + L’utilisateur "[2]" a déjà lancé l’installation du produit "[3]". Il devra exécuter à nouveau cette installation avant de pouvoir utiliser le produit. + Espace disque insuffisant -- Volume : "[2]" + Le fichier [2][3] est utilisé{ par Nom : [4], Identifiant : [5], Titre de fenêtre : "[6]"}. Fermez ce programme, puis réessayez. + Le programme "[2]" est déjà installé, ce qui empêche l’installation de ce programme. Les deux programmes ne sont pas compatibles. + Espace insuffisant sur le volume "[2]" pour continuer l’installation avec l’option de récupération. [3] Ko sont requis, alors que seuls [4] Ko sont disponibles. Cliquez sur Ignorer pour poursuivre l’installation sans enregistrer les informations de récupération, cliquez sur Recommencer pour revérifier l’espace libre, ou cliquez sur Annuler pour arrêter. + Impossible d’accéder à l’emplacement réseau [2]. + Fermez les programmes suivants avant de poursuivre l’installation : + Une erreur s’est produite lors de l’activation des paramètres de sécurité. [2] n’est pas un nom de groupe ou d’utilisateur reconnu. Le problème peut provenir du package ou de la connexion au contrôleur de domaine sur le réseau. Vérifiez vos connexions réseau et cliquez sur Recommencer, ou cliquez sur Annuler pour arrêter. {{SID de l’utilisateur, erreur système [3]}} + Le programme d’installation doit redémarrer votre système pour valider les modifications apportées à [2]. Cliquez sur Oui pour redémarrer maintenant, ou sur Non si vous voulez redémarrer manuellement ultérieurement. + Un package d’installation du programme [2] est introuvable. Exécutez le programme d’installation avec une copie valide du package d’installation "[3]". + Echec de l’installation. + Vous pouvez restaurer l’état antérieur de votre ordinateur ou poursuivre l’installation ultérieurement. Voulez-vous restaurer votre ordinateur ? + Une erreur s’est produite lors de l’écriture des informations concernant l’installation sur le disque. Vérifiez que l’espace disponible sur le disque est suffisant et cliquez sur Recommencer, ou cliquez sur Annuler pour mettre fin à l’installation. + Impossible de trouver un ou plusieurs des fichiers requis pour restaurer l’état antérieur de votre ordinateur. Impossible de procéder à la restauration. + La version précédente de [2] ne peut pas être supprimée. Contactez votre support technique. {{Erreur système [3].}} + Impossible d’accéder au service Windows Installer. Ceci peut se produire si Windows est en mode Sans échec, ou si le programme d’installation de Windows n’est pas bien installé. Contactez votre support technique pour assistance. + Problème détecté dans ce package d’installation Windows. Un script requis pour cette installation n’a pas pu être lancé. Contactez votre support technique ou l’éditeur du package. {{Action personnalisée [2] erreur de script [3], [4] : [5] ligne [6], colonne [7], [8] }} + Problème détecté dans ce package d’installation Windows. Un programme requis pour cette installation n’a pas pu être lancé. Contactez votre support technique ou l’éditeur du package. {{Action : [2], emplacement : [3], commande : [4] }} + Problème détecté dans ce package d’installation Windows. Un programme lancé dans le cadre de l’installation ne s’est pas terminé normalement. Contactez votre support technique ou l’éditeur du package. {{Action [2], emplacement : [3], commande : [4] }} + Problème détecté dans ce package d’installation Windows. Un fichier DLL requis pour cette installation n’a pas pu être ouvert. Contactez votre support technique ou l’éditeur du package. {{Action [2], entrée : [3], bibliothèque : [4] }} + Echec de la suppression. + Echec de l’annonce. + Echec de la configuration. + Pour supprimer ce programme, ouvrez une session avec un compte d’administrateur ou contactez votre support technique pour assistance. + Le package d’installation source du produit [2] n’est pas synchronisé avec le package client. Exécutez de nouveau le programme d’installation à l’aide d’une copie du package d’installation "[3]" valide. + Pour terminer l’installation de [2], vous devez redémarrer l’ordinateur. D’autres utilisateurs ont ouvert une session sur cet ordinateur et un redémarrage pourraient leur faire perdre leur travail. Voulez-vous redémarrer maintenant ? + Le chemin d’accès [2] n’est pas valide. Entrez un chemin d’accès valide. + Le lecteur [2] est vide. Insérez un disque et cliquez sur Recommencer, ou cliquez sur Annuler pour revenir dans la boîte de dialogue Sélection de l’emplacement et sélectionner un autre volume. + Dossier [2] inexistant. Entrez le chemin d’accès d’un dossier existant. + Le programme d’installation n’a pas pu déterminer un dossier de destination valide pour l’installation. + Erreur lors d’une tentative de lecture de la base de données d’installation source : [2]. + Planification du redémarrage : le fichier [2] est renommé [3]. Pour achever l’opération, votre système doit être redémarré. + Planification du redémarrage : suppression du fichier [2]. Pour achever l’opération, votre système doit être redémarré. + Impossible d’enregistrer le module [2]. HRESULT [3]. Contactez votre service de support technique. + Impossible d’annuler l’enregistrement du module [2]. HRESULT [3]. Contactez votre service de support technique. + Impossible d’enregistrer la police [2]. Vérifiez que les autorisations dont vous disposez sont suffisantes pour installer des polices et que le système prend en charge cette police en particulier. + Impossible d’annuler l’enregistrement de la police [2]. Vérifiez que les autorisations dont vous disposez sont suffisantes pour supprimer des polices. + Impossible d’enregistrer la bibliothèque de types pour le fichier [2]. Contactez votre service de support technique. + Impossible d’annuler l’enregistrement de la bibliothèque de types pour le fichier [2]. Contactez votre support technique. + Erreur lors de l’installation du gestionnaire de pilotes ODBC. Erreur ODBC [2] : [3]. Contactez votre service de support technique. + Erreur lors de l’installation du pilote ODBC [4]. Erreur ODBC [2] : [3]. Vérifiez que le fichier [4] existe et que vous êtes autorisé à y accéder. + Echec du démarrage du service "[2]" ([3]). Vérifiez que vous disposez de privilèges suffisants pour démarrer les services système. + Impossible d’arrêter le service "[2]" ([3]). Vérifiez que vous disposez de privilèges suffisants pour arrêter les services système. + Impossible de supprimer le service "[2]" ([3]). Vérifiez que vous disposez de privilèges suffisants pour supprimer les services système. + Impossible d’installer le service "[2]" ([3]). Vérifiez que vous disposez de privilèges suffisants pour installer des services système. + Impossible de mettre à jour la variable d’environnement "[2]". Vérifiez que vous disposez de privilèges suffisants pour modifier les variables d’environnement. + Vous ne disposez pas des privilèges suffisants pour exécuter cette installation pour tous les utilisateurs de cet ordinateur. Ouvrez une session en tant qu’administrateur, puis réexécutez le programme d’installation. + Impossible de définir la sécurité du fichier "[3]". Erreur [2]. Vérifiez que vous disposez des privilèges suffisants pour modifier les autorisations de sécurité sur ce fichier. + Erreur lors de l’enregistrement de l’application COM+. Contactez votre support technique pour plus d’informations. + Erreur lors de l’annulation de l’enregistrement de l’application COM+. Contactez votre support technique pour plus d’informations. + La description du service "[2]" ([3]) n’a pas pu être modifiée. + Le service Windows Installer ne peut pas mettre à jour le fichier système [2] car le fichier est protégé par Windows. Vous devrez peut-être mettre à jour votre système d’exploitation pour que ce programme fonctionne correctement. {{Version de package : [3], version protégée du système d’exploitation : [4]}} + Le service Windows Installer ne peut pas mettre à jour le fichier Windows protégé [2]. {{Version du package : [3], version protégée du système d’exploitation : [4], erreur SFP : [5]}} + Le service d’installation Windows ne peut pas mettre à jour certains fichiers Windows protégés. {{Erreur SFP : [2]. Liste des fichiers protégés :\r\n[3]}}" + Les autorisations d’installation sont désactivées via la stratégie de sécurité sur cet ordinateur. + Une erreur s’est produite lors de l’installation du module "[6]". Reportez-vous à l’aide et au support pour plus d’informations. HRESULT : [3]. {{interface de module : [4], fonctionnalité : [5], composant : [2]}} + Une erreur s’est produite lors de l’installation du module "[6]". Le module ne porte pas de nom fort ou n’est pas signé avec la longueur de clé minimale. HRESULT : [3]. {{interface de module : [4], fonctionnalité : [5], composant : [2]}} + Une erreur s’est produite lors de l’installation du module "[6]". La signature ou le catalogue n’a pu être vérifié ou n’est pas valide. HRESULT : [3]. {{interface de module : [4], fonctionnalité : [5], composant : [2]}} + Une erreur s’est produite lors de l’installation du module "[6]". Un ou plusieurs modules sont introuvables. HRESULT : [3]. {{interface de module : [4], fonctionnalité : [5], composant : [2]}} + Tous les composants de cette fonctionnalité seront indisponibles + Cette fonctionnalité deviendra indisponible + Sera installé(e) à la demande + Le programme d’installation détermine l’espace disque nécessaire pour cette fonctionnalité... \ No newline at end of file diff --git a/installer/win/BrowseDlg.wxs b/installer/win/BrowseDlg.wxs new file mode 100644 index 000000000..1daeb491b --- /dev/null +++ b/installer/win/BrowseDlg.wxs @@ -0,0 +1,46 @@ + + + + + + + + + 1 + 1 + + + 1 + 1 + + + + + + + 1 + + + 1 + + + + + + + + + + + + \ No newline at end of file diff --git a/installer/win/ExitDialog.wxs b/installer/win/ExitDialog.wxs index 947cfb88b..a93ba359c 100644 --- a/installer/win/ExitDialog.wxs +++ b/installer/win/ExitDialog.wxs @@ -10,10 +10,13 @@ You must not remove this notice, or any other, from this software. --> + - + @@ -26,10 +29,18 @@ - - diff --git a/installer/win/InstallDirDlg.wxs b/installer/win/InstallDirDlg.wxs index 993ae2485..400d248e0 100644 --- a/installer/win/InstallDirDlg.wxs +++ b/installer/win/InstallDirDlg.wxs @@ -10,26 +10,32 @@ You must not remove this notice, or any other, from this software. --> + - + 1 - - + + - + + + NOT Installed + diff --git a/installer/win/LicenseAgreementDlg.wxs b/installer/win/LicenseAgreementDlg.wxs index a43308c1c..8907d1c64 100644 --- a/installer/win/LicenseAgreementDlg.wxs +++ b/installer/win/LicenseAgreementDlg.wxs @@ -10,6 +10,9 @@ You must not remove this notice, or any other, from this software. --> + @@ -35,7 +38,7 @@ - + diff --git a/installer/win/MaintenanceWelcomeDlg.wxs b/installer/win/MaintenanceWelcomeDlg.wxs index 1be38f16c..673f20683 100644 --- a/installer/win/MaintenanceWelcomeDlg.wxs +++ b/installer/win/MaintenanceWelcomeDlg.wxs @@ -10,10 +10,13 @@ You must not remove this notice, or any other, from this software. --> + - + - + + + Installed + \ No newline at end of file diff --git a/installer/win/MaintenanceWelcomeDlg_src.wxs b/installer/win/MaintenanceWelcomeDlg_src.wxs index 5b9660abf..8d49636ea 100644 --- a/installer/win/MaintenanceWelcomeDlg_src.wxs +++ b/installer/win/MaintenanceWelcomeDlg_src.wxs @@ -10,6 +10,9 @@ You must not remove this notice, or any other, from this software. --> + diff --git a/installer/win/PrepareDlg.wxs b/installer/win/PrepareDlg.wxs index 2f131a442..f16d80508 100644 --- a/installer/win/PrepareDlg.wxs +++ b/installer/win/PrepareDlg.wxs @@ -10,6 +10,9 @@ You must not remove this notice, or any other, from this software. --> + diff --git a/installer/win/ProgressDlg.wxs b/installer/win/ProgressDlg.wxs index 4bf82962f..4160e0fdc 100644 --- a/installer/win/ProgressDlg.wxs +++ b/installer/win/ProgressDlg.wxs @@ -10,10 +10,13 @@ You must not remove this notice, or any other, from this software. --> + - + 1 @@ -24,13 +27,13 @@ - + + + + + \ No newline at end of file diff --git a/installer/win/README.MD b/installer/win/README.MD index a27529245..34f9cb6cd 100644 --- a/installer/win/README.MD +++ b/installer/win/README.MD @@ -1,26 +1,53 @@ ## Overview This readme describes how the .msi installer is created for Brackets on Windows. -_**Note:**_ currently, the scripts will only run from a certain hardcoded location on the build machine. The -scripts are only checked into git for backup. Any changes made to the scripts in brackets-shell\installer\win -must be manually copied to F:\stage\Brackets\InstallerFiles to take effect. + +## System setup +Normally, the installer scripts are run from a specific pre-set-up build machine. These are instructions for setting up a _new_ build machine: + +1. Download Ant; unzip it into a path (ideally a path with no spaces -- see below) +2. Download & install a JDK (the full SDK, _not_ just a JRE) +3. Set `ANT_HOME` to the path to Ant. Must not contain spaces -- if target dir does have spaces, use the DOS-style path mapping (e.g. `c:\progra~1\...`) +4. Set `JAVA_HOME` to the path to Java. Must not contain spaces -- same as above. +5. Add `%ANT_HOME%\bin` to the PATH +6. Download & install Wix 3.5 +7. Get the MsiTran.exe tool: + * Option A: If you have Visual Studio installed, look in C:\Program Files\Microsoft SDKs\Windows\v??\bin to locate it + * Option B: Follow the [instructions here](http://www.geektieguy.com/2010/03/13/create-a-multi-lingual-multi-language-msi-using-wix-and-custom-build-scripts/) to + download the Windows SDK ISO and extract just the bit you need + * Option C: Download the [full Windows SDK online installer](http://www.microsoft.com/en-us/download/details.aspx?id=3138). On + the "Installation Options" screen, uncheck everything but "Win32 Development Tools" + * Copy it to _(wix-install-dir)_\bin +8. Get the WiSubStg.vbs and WiLangId.vbs scripts: + * Option A: Follow the [instructions here](http://www.geektieguy.com/2010/03/13/create-a-multi-lingual-multi-language-msi-using-wix-and-custom-build-scripts/) to + download the Windows SDK ISO and extract just the bit you need + * Option B: Download the [full Windows SDK online installer](http://www.microsoft.com/en-us/download/details.aspx?id=3138). On + the "Installation Options" screen, uncheck everything but "Samples" + * Copy these two files to _(wix-install-dir)_\bin +9. You may need to locally edit `wix.base` in brackets-win-install-build.xml if the Wix install folder doesn't match what's hardcoded there +10. `git clone` the brackets and brackets-shell Git repos +11. Set `BRACKETS_SRC` to the root folder of the brackets repo ## To rev the Brackets sprint/build number -_**TODO: This is currently hardcoded in multiple places in brackets-win-install-build.xml and Brackets.wxs**_ +1. Open brackets-win-install-build.xml and change `product.sprint.number` ## To build the Brackets installer -1. Build brackets-shell +1. Sync both the brackets and brackets-shell repos + * Be sure to update submodules in brackets + * Double check that your git status is clean +2. Build brackets-shell * This cannot be done on the build machine yet, so generate a copy elsewhere and copy it into brackets-shell\Release on the build machine -2. Follow instructions in brackets-shell\installer\win\stageForInstaller.bat to run it +3. Follow instructions in brackets-shell\installer\win\stageForInstaller.bat to run it * This will generate brackets-shell\installer\win\staging -3. Copy contents of brackets-shell\installer\win\staging to F:\stage\Brackets\BinarySource -4. Update build numbers as needed (see previous section) -5. Go to F:\stage\Brackets\InstallerFiles -6. Run `ant -f brackets-win-install-build.xml -Dofficial.build.number=1 build.mul` - * Output is in F:\stage\Brackets\InstallerFiles\Brackets Sprint NN.msi +4. Follow instructions in brackets-shell\installer\win\setBuildNumber.sh to run it + * This will inject the build number, branch, and SHA into the staged package.json file +5. Update build numbers as needed (see previous section) +6. Run `ant -f brackets-win-install-build.xml` in installer\win\staging + * Output is "Brackets Sprint _NN_.msi" + * This creates lots of intermediate files, too. To clean them up, run the `clean.temp` target * Note: you'll see four warning messages saying "The file ... is not a Font, and its version is not a companion file reference." These are safe to ignore - see issue #1471. - (Just make sure the *end* of each chunk of output doesn't list any errors). \ No newline at end of file + (Just make sure the *end* of each chunk of output doesn't list any errors). diff --git a/installer/win/ResumeDlg.wxs b/installer/win/ResumeDlg.wxs index 137ac00e7..8fe007847 100644 --- a/installer/win/ResumeDlg.wxs +++ b/installer/win/ResumeDlg.wxs @@ -10,6 +10,9 @@ You must not remove this notice, or any other, from this software. --> + diff --git a/installer/win/UserExit.wxs b/installer/win/UserExit.wxs index 9d43b7413..461482689 100644 --- a/installer/win/UserExit.wxs +++ b/installer/win/UserExit.wxs @@ -10,17 +10,20 @@ You must not remove this notice, or any other, from this software. --> + - + 1 - + diff --git a/installer/win/VerifyReadyDlg.wxs b/installer/win/VerifyReadyDlg.wxs index 934435dea..58cbe2783 100644 --- a/installer/win/VerifyReadyDlg.wxs +++ b/installer/win/VerifyReadyDlg.wxs @@ -10,10 +10,13 @@ You must not remove this notice, or any other, from this software. --> + - + - - - - -