mirror of
https://github.com/FirestormViewer/phoenix-firestorm.git
synced 2026-08-14 00:48:30 +00:00
Merge branch 'main' of https://github.com/secondlife/viewer
# Conflicts: # .github/workflows/build.yaml # indra/cmake/Python.cmake # indra/cmake/Velopack.cmake # indra/lib/python/indra/util/llmanifest.py # indra/newview/CMakeLists.txt # indra/newview/app_settings/settings.xml # indra/newview/installers/windows/installer_template.nsi # indra/newview/llappviewer.cpp # indra/newview/llappviewerwin32.cpp # indra/newview/llpanellogin.cpp # indra/newview/llstartup.cpp # indra/newview/llvelopack.cpp # indra/newview/llvelopack.h # indra/newview/skins/default/xui/en/notifications.xml # indra/newview/viewer_manifest.py
This commit is contained in:
@@ -345,7 +345,7 @@ jobs:
|
||||
steps:
|
||||
- name: Sign and package Windows viewer
|
||||
if: env.AZURE_KEY_VAULT_URI && env.AZURE_CERT_NAME && env.AZURE_CLIENT_ID && env.AZURE_CLIENT_SECRET && env.AZURE_TENANT_ID
|
||||
uses: secondlife/viewer-build-util/sign-pkg-windows@geenz/velopack
|
||||
uses: secondlife/viewer-build-util/sign-pkg-windows@v2.1.0
|
||||
with:
|
||||
vault_uri: "${{ env.AZURE_KEY_VAULT_URI }}"
|
||||
cert_name: "${{ env.AZURE_CERT_NAME }}"
|
||||
@@ -392,7 +392,7 @@ jobs:
|
||||
|
||||
- name: Sign and package Mac viewer
|
||||
if: env.SIGNING_CERT_MACOS && env.SIGNING_CERT_MACOS_IDENTITY && env.SIGNING_CERT_MACOS_PASSWORD && steps.note-creds.outputs.note_user && steps.note-creds.outputs.note_pass && steps.note-creds.outputs.note_team
|
||||
uses: secondlife/viewer-build-util/sign-pkg-mac@geenz/velopack
|
||||
uses: secondlife/viewer-build-util/sign-pkg-mac@v2.1.0
|
||||
with:
|
||||
channel: ${{ needs.build.outputs.viewer_channel }}
|
||||
imagename: ${{ needs.build.outputs.imagename }}
|
||||
|
||||
@@ -21,7 +21,9 @@ on:
|
||||
project:
|
||||
description: "Project Name (used for channel name in project builds, and tag name for all builds)"
|
||||
default: "hippo"
|
||||
# TODO - add an input for selecting another sha to build other than head of branch
|
||||
tag_override:
|
||||
description: "Override the tag name (optional). If the tag already exists, a numeric suffix is appended."
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
tag-release:
|
||||
@@ -34,7 +36,7 @@ jobs:
|
||||
NIGHTLY_DATE=$(date --rfc-3339=date)
|
||||
echo NIGHTLY_DATE=${NIGHTLY_DATE} >> ${GITHUB_ENV}
|
||||
echo TAG_ID="$(echo ${{ github.sha }} | cut -c1-8)-${{ inputs.project || '${NIGHTLY_DATE}' }}" >> ${GITHUB_ENV}
|
||||
- name: Update Tag
|
||||
- name: Create Tag
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
# use a real access token instead of GITHUB_TOKEN default.
|
||||
@@ -44,9 +46,27 @@ jobs:
|
||||
# this token will need to be renewed anually in January
|
||||
github-token: ${{ secrets.LL_TAG_RELEASE_TOKEN }}
|
||||
script: |
|
||||
github.rest.git.createRef({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: "refs/tags/${{ env.VIEWER_CHANNEL }}#${{ env.TAG_ID }}",
|
||||
sha: context.sha
|
||||
})
|
||||
const override = `${{ inputs.tag_override }}`.trim();
|
||||
const baseTag = override || `${{ env.VIEWER_CHANNEL }}#${{ env.TAG_ID }}`;
|
||||
|
||||
// Try the base tag first, then append -2, -3, etc. if it already exists
|
||||
let tag = baseTag;
|
||||
for (let attempt = 1; ; attempt++) {
|
||||
try {
|
||||
await github.rest.git.createRef({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: `refs/tags/${tag}`,
|
||||
sha: context.sha
|
||||
});
|
||||
core.info(`Created tag: ${tag}`);
|
||||
break;
|
||||
} catch (e) {
|
||||
if (e.status === 422 && attempt < 10) {
|
||||
core.info(`Tag '${tag}' already exists, trying next suffix...`);
|
||||
tag = `${baseTag}-${attempt + 1}`;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6965,6 +6965,17 @@
|
||||
<key>Backup</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>PreviousInstallChecked</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether viewer checked previous install on the same channel for NSIS</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>LastInstallVersion</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -17267,11 +17278,11 @@ Change of this parameter will affect the layout of buttons in notification toast
|
||||
<key>UpdaterShowReleaseNotes</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enables displaying of the Release notes in a web floater after update.</string>
|
||||
<string>Enables displaying of the Release notes in a web floater after update. 0 - don't show, 1 - show, 2 - show even for test viewers</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
|
||||
@@ -1172,21 +1172,21 @@ Function .onInstSuccess
|
||||
# </FS:Ansariel>
|
||||
|
||||
Call CheckWindowsServPack # Warn if not on the latest SP before asking to launch.
|
||||
# <FS:PP> Disable autorun
|
||||
#StrCmp $SKIP_AUTORUN "true" +2;
|
||||
StrCmp $SKIP_DIALOGS "true" label_launch
|
||||
|
||||
${GetOptions} $COMMANDLINE "/AUTOSTART" $R0
|
||||
# If parameter was there (no error) just launch
|
||||
# Otherwise ask
|
||||
IfErrors label_ask_launch label_launch
|
||||
|
||||
label_ask_launch:
|
||||
# Don't launch by default when silent
|
||||
IfSilent label_no_launch
|
||||
MessageBox MB_YESNO $(InstSuccesssQuestion) IDYES label_launch IDNO label_no_launch
|
||||
|
||||
label_launch:
|
||||
# <FS:PP> Disable autorun
|
||||
#StrCmp $SKIP_AUTORUN "true" +2;
|
||||
StrCmp $SKIP_DIALOGS "true" label_launch
|
||||
|
||||
${GetOptions} $COMMANDLINE "/AUTOSTART" $R0
|
||||
# If parameter was there (no error) just launch
|
||||
# Otherwise ask
|
||||
IfErrors label_ask_launch label_launch
|
||||
|
||||
label_ask_launch:
|
||||
# Don't launch by default when silent
|
||||
IfSilent label_no_launch
|
||||
MessageBox MB_YESNO $(InstSuccesssQuestion) IDYES label_launch IDNO label_no_launch
|
||||
|
||||
label_launch:
|
||||
Exec '"$INSTDIR\$VIEWER_EXE" $SHORTCUT_LANG_PARAM'
|
||||
|
||||
label_no_launch:
|
||||
|
||||
@@ -443,18 +443,6 @@ const std::string ERROR_MARKER_FILE_NAME(SAFE_FILE_NAME_PREFIX + ".error_marker"
|
||||
const std::string LOGOUT_MARKER_FILE_NAME(SAFE_FILE_NAME_PREFIX + ".logout_marker"); //FS orig modified LL
|
||||
static std::string gLaunchFileOnQuit;
|
||||
|
||||
// Used on Win32 for other apps to identify our window (eg, win_setup)
|
||||
#if LL_VELOPACK
|
||||
// Velopack is deliberately different fron NSIS to not prevent nsis uninstall
|
||||
const char* const VIEWER_WINDOW_CLASSNAME = "Second\u00A0Life"; // no break space
|
||||
#else
|
||||
// NSIS relies on this to detect if viewer is up.
|
||||
// NSIS's method is somewhat unreliable since window
|
||||
// can close long before cleanup is done
|
||||
// Note: Changing this breaks compatibility with SLURL handling, try to avoid it.
|
||||
const char* const VIEWER_WINDOW_CLASSNAME = "Second Life";
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// List of entries from strings.xml to always replace
|
||||
@@ -3740,7 +3728,7 @@ bool LLAppViewer::initWindow()
|
||||
LLViewerWindow::Params window_params;
|
||||
window_params
|
||||
.title(gWindowTitle)
|
||||
.name(VIEWER_WINDOW_CLASSNAME)
|
||||
.name(sWindowClass)
|
||||
.x(gSavedSettings.getS32("WindowX"))
|
||||
.y(gSavedSettings.getS32("WindowY"))
|
||||
.width(gSavedSettings.getU32("WindowWidth"))
|
||||
|
||||
@@ -287,6 +287,14 @@ protected:
|
||||
|
||||
virtual void sendOutOfDiskSpaceNotification();
|
||||
|
||||
protected:
|
||||
|
||||
// NSIS relies on this to detect if viewer is up.
|
||||
// NSIS's method is somewhat unreliable since window
|
||||
// can close long before cleanup is done.
|
||||
// sendURLToOtherInstance also relies on this to detect if viewer is up.
|
||||
static constexpr const char* sWindowClass = "Second Life";
|
||||
|
||||
private:
|
||||
|
||||
bool doFrame();
|
||||
|
||||
@@ -291,7 +291,6 @@ LONG WINAPI catchallCrashHandler(EXCEPTION_POINTERS * /*ExceptionInfo*/)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::string LLAppViewerWin32::sWindowClass = "Second Life";
|
||||
|
||||
/*
|
||||
This function is used to print to the command line a text message
|
||||
@@ -509,9 +508,10 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
|
||||
LLControlGroup settings("global");
|
||||
if (settings.loadFromFile(user_settings_path))
|
||||
{
|
||||
if (settings.controlExists("LastInstallVersion"))
|
||||
// If user reinstalls or updates, we want to recheck for nsis leftovers.
|
||||
if (settings.controlExists("PreviousInstallChecked"))
|
||||
{
|
||||
settings.setString("LastInstallVersion", std::string());
|
||||
settings.setBOOL("PreviousInstallChecked", false);
|
||||
}
|
||||
settings.saveToFile(user_settings_path, true);
|
||||
}
|
||||
@@ -1207,7 +1207,7 @@ bool LLAppViewerWin32::restoreErrorTrap()
|
||||
bool LLAppViewerWin32::sendURLToOtherInstance(const std::string& url)
|
||||
{
|
||||
wchar_t window_class[256]; /* Flawfinder: ignore */ // Assume max length < 255 chars.
|
||||
mbstowcs(window_class, sWindowClass.c_str(), 255);
|
||||
mbstowcs(window_class, sWindowClass, 255);
|
||||
window_class[255] = 0;
|
||||
// Use the class instead of the window name.
|
||||
HWND other_window = FindWindow(window_class, NULL);
|
||||
|
||||
@@ -59,8 +59,6 @@ protected:
|
||||
|
||||
std::string generateSerialNumber();
|
||||
|
||||
static const std::string sWindowClass;
|
||||
|
||||
private:
|
||||
void disableWinErrorReporting();
|
||||
void bugsplatAddStaticAttributes(const LLSD& info) override; // <FS:Beq> override for windows attributes
|
||||
|
||||
+49
-54
@@ -3563,72 +3563,57 @@ void release_notes_coro(const std::string url)
|
||||
void uninstall_nsis_if_required()
|
||||
{
|
||||
#if LL_VELOPACK && LL_WINDOWS
|
||||
std::string last_install_ver = gSavedSettings.getString("LastInstallVersion");
|
||||
if (!last_install_ver.empty())
|
||||
bool checked_for_legacy_install = gSavedSettings.getBOOL("PreviousInstallChecked");
|
||||
if (checked_for_legacy_install)
|
||||
{
|
||||
return;
|
||||
}
|
||||
LLVersionInfo* ver_inst = LLVersionInfo::getInstance();
|
||||
gSavedSettings.setString("LastInstallVersion",
|
||||
ver_inst->getChannelAndVersion());
|
||||
|
||||
if (LLNotifications::instance().getIgnored("PromptRemoveNsisInstallation"))
|
||||
{
|
||||
// By default 'ignore' returns default button, which is uninstall
|
||||
// for PromptRemoveNsisInstallation, but while we want the button
|
||||
// to be the default, we don't want a scary UAC without a notice
|
||||
// as a default action, so if this notification is ignored,
|
||||
// we will treat it as if user is going to cancel the uninstall.
|
||||
return;
|
||||
}
|
||||
gSavedSettings.setBOOL("PreviousInstallChecked", true);
|
||||
|
||||
LL_INFOS() << "Looking for previous NSIS installs" << LL_ENDL;
|
||||
|
||||
wchar_t buffer[MAX_PATH];
|
||||
if (!get_nsis_uninstaller_path( buffer,
|
||||
MAX_PATH,
|
||||
ver_inst->getMajor(),
|
||||
ver_inst->getMinor(),
|
||||
ver_inst->getPatch(),
|
||||
ver_inst->getBuild())
|
||||
)
|
||||
S32 found_major = 0;
|
||||
S32 found_minor = 0;
|
||||
S32 found_patch = 0;
|
||||
U64 found_build = 0;
|
||||
|
||||
if (!get_nsis_version(found_major, found_minor, found_patch, found_build))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Compose command line: "<uninstaller_path>" /S /clearreg
|
||||
std::wstring params = L"\"";
|
||||
params += buffer;
|
||||
params += L"\"";
|
||||
// params += L" /S /clearreg"; // silent uninstall and clear registry entries
|
||||
LLVersionInfo* ver_inst = LLVersionInfo::getInstance();
|
||||
|
||||
LLNotificationsUtil::add("PromptRemoveNsisInstallation", LLSD(), LLSD(),
|
||||
[params](const LLSD& notification, const LLSD& response)
|
||||
if (found_major > ver_inst->getMajor())
|
||||
{
|
||||
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
||||
if (option == 1) // cancel
|
||||
{
|
||||
return;
|
||||
}
|
||||
LL_INFOS() << "Found installed nsis version that is newer" << found_major << "." << found_minor << "." << found_patch << "." << found_build << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
LL_INFOS() << "Triggering NSIS uninstall from " << ll_convert_wide_to_string(params) << LL_ENDL;
|
||||
if (found_major == ver_inst->getMajor()
|
||||
&& found_minor > ver_inst->getMinor())
|
||||
{
|
||||
LL_INFOS() << "Found installed nsis version that is newer" << found_major << "." << found_minor << "." << found_patch << "." << found_build << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Launch uninstaller using explorer.exe
|
||||
SHELLEXECUTEINFOW sei = { 0 };
|
||||
sei.cbSize = sizeof(sei);
|
||||
sei.fMask = SEE_MASK_DEFAULT;
|
||||
sei.hwnd = NULL;
|
||||
sei.lpVerb = L"runas"; // Request elevation
|
||||
sei.lpFile = L"explorer.exe";
|
||||
sei.lpParameters = params.c_str();
|
||||
if (found_major == ver_inst->getMajor()
|
||||
&& found_minor == ver_inst->getMinor()
|
||||
&& found_patch > ver_inst->getPatch())
|
||||
{
|
||||
LL_INFOS() << "Found installed nsis version that is newer" << found_major << "." << found_minor << "." << found_patch << "." << found_build << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
sei.nShow = SW_HIDE;
|
||||
// Assume that nsis is going to be something like x.x.x, while velopack is x.x.(x+1),
|
||||
// so there is no point to check build.
|
||||
LL_INFOS() << "Found NSIS install " << found_major << "." << found_minor << "." << found_patch << "." << found_build << LL_ENDL;
|
||||
|
||||
if (!ShellExecuteExW(&sei))
|
||||
{
|
||||
LL_WARNS("AppInit") << "Failed to launch NSIS uninstaller, error code: " << GetLastError() << LL_ENDL;
|
||||
}
|
||||
});
|
||||
clear_nsis_links();
|
||||
|
||||
LLSD args;
|
||||
args["VERSION"] = llformat("%d.%d.%d", found_major, found_minor, found_patch);
|
||||
LLNotificationsUtil::add("FoundLegacyNsisInstallation", args);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -3665,10 +3650,20 @@ void show_release_notes_if_required()
|
||||
// below. If viewer release notes stop working, might be because that
|
||||
// LLEventMailDrop got moved out of LLVersionInfo and hasn't yet been
|
||||
// instantiated.
|
||||
if (!release_notes_shown && (LLVersionInfo::instance().getChannelAndVersion() != gLastRunVersion)
|
||||
&& LLVersionInfo::instance().getViewerMaturity() != LLVersionInfo::TEST_VIEWER // don't show Release Notes for the test builds
|
||||
&& gSavedSettings.getBOOL("UpdaterShowReleaseNotes")
|
||||
&& !gSavedSettings.getBOOL("FirstLoginThisInstall"))
|
||||
if (release_notes_shown
|
||||
|| LLVersionInfo::instance().getChannelAndVersion() == gLastRunVersion
|
||||
|| gSavedSettings.getBOOL("FirstLoginThisInstall")) // New users don't need to see release notes
|
||||
{
|
||||
return;
|
||||
}
|
||||
S32 mode = gSavedSettings.getS32("UpdaterShowReleaseNotes");
|
||||
if (mode == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (mode == 2 // Show even for test builds
|
||||
|| LLVersionInfo::instance().getViewerMaturity() != LLVersionInfo::TEST_VIEWER) // don't show Release Notes for the test builds
|
||||
|
||||
{
|
||||
|
||||
#if LL_RELEASE_FOR_DOWNLOAD
|
||||
|
||||
@@ -405,6 +405,50 @@ static void register_protocol_handler(const std::wstring& protocol,
|
||||
}
|
||||
}
|
||||
|
||||
void clear_nsis_links()
|
||||
{
|
||||
wchar_t path[MAX_PATH];
|
||||
|
||||
// 1. The 'start' shortcuts set by nsis would be global, like app shortcut:
|
||||
// C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Second Life Viewer\Second Life Viewer.lnk
|
||||
// But it isn't just one link, it's a whole directory that needs to be removed.
|
||||
if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_COMMON_PROGRAMS, NULL, 0, path)))
|
||||
{
|
||||
std::wstring start_menu_path = path;
|
||||
std::wstring folder_path = start_menu_path + L"\\" + get_app_name();
|
||||
|
||||
std::error_code ec;
|
||||
std::filesystem::path dir(folder_path);
|
||||
if (std::filesystem::exists(dir, ec))
|
||||
{
|
||||
std::filesystem::remove_all(dir, ec);
|
||||
if (ec)
|
||||
{
|
||||
LL_WARNS("Velopack") << "Failed to remove NSIS start menu directory: "
|
||||
<< ll_convert_wide_to_string(folder_path) << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Desktop link, also a global one.
|
||||
// C:\Users\Public\Desktop
|
||||
if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, 0, path)))
|
||||
{
|
||||
std::wstring desktop_path = path;
|
||||
std::wstring shortcut_path = desktop_path + L"\\" + get_app_name() + L".lnk";
|
||||
if (!DeleteFileW(shortcut_path.c_str()))
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
if (error != ERROR_FILE_NOT_FOUND)
|
||||
{
|
||||
LL_WARNS("Velopack") << "Failed to delete NSIS desktop shortcut: "
|
||||
<< ll_convert_wide_to_string(shortcut_path)
|
||||
<< " (error: " << error << ")" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_version(const wchar_t* version_str, int& major, int& minor, int& patch, uint64_t& build)
|
||||
{
|
||||
major = minor = patch = 0;
|
||||
@@ -414,7 +458,11 @@ static void parse_version(const wchar_t* version_str, int& major, int& minor, in
|
||||
swscanf(version_str, L"%d.%d.%d.%llu", &major, &minor, &patch, &build);
|
||||
}
|
||||
|
||||
bool get_nsis_uninstaller_path(wchar_t* path_buffer, DWORD bufSize, S32 cur_major_ver, S32 cur_minor_ver, S32 cur_patch_ver, U64 cur_build_ver)
|
||||
bool get_nsis_version(
|
||||
int& nsis_major,
|
||||
int& nsis_minor,
|
||||
int& nsis_patch,
|
||||
uint64_t& nsis_build)
|
||||
{
|
||||
// Test for presence of NSIS viewer registration, then
|
||||
// attempt to read uninstall info
|
||||
@@ -439,23 +487,12 @@ bool get_nsis_uninstaller_path(wchar_t* path_buffer, DWORD bufSize, S32 cur_majo
|
||||
return false;
|
||||
}
|
||||
|
||||
int nsis_major = 0, nsis_minor = 0, nsis_patch = 0;
|
||||
uint64_t nsis_build = 0;
|
||||
parse_version(version_buf, nsis_major, nsis_minor, nsis_patch, nsis_build);
|
||||
|
||||
// Compare numerically
|
||||
if ((nsis_major > cur_major_ver) ||
|
||||
(nsis_major == cur_major_ver && nsis_minor > cur_minor_ver) ||
|
||||
(nsis_major == cur_major_ver && nsis_minor == cur_minor_ver && nsis_patch > cur_patch_ver) ||
|
||||
// Assume that bigger build number means newer version, which is not always true but works for our purposes
|
||||
(nsis_major == cur_major_ver && nsis_minor == cur_minor_ver && nsis_patch == cur_patch_ver && nsis_build > cur_build_ver))
|
||||
{
|
||||
LL_INFOS() << "Found installed nsis version that is newer" << nsis_major << "." << nsis_minor << "." << nsis_patch << LL_ENDL;
|
||||
RegCloseKey(hkey);
|
||||
return false;
|
||||
}
|
||||
|
||||
LONG rv = RegGetValueW(hkey, nullptr, L"UninstallString", RRF_RT_REG_SZ, &type, path_buffer, &bufSize);
|
||||
// Make sure it actually exists and not a dead entry.
|
||||
wchar_t path_buffer[MAX_PATH] = { 0 };
|
||||
DWORD path_buf_size = sizeof(path_buffer);
|
||||
LONG rv = RegGetValueW(hkey, nullptr, L"UninstallString", RRF_RT_REG_SZ, &type, path_buffer, &path_buf_size);
|
||||
RegCloseKey(hkey);
|
||||
if (rv != ERROR_SUCCESS)
|
||||
{
|
||||
@@ -499,10 +536,15 @@ static void register_uninstall_info(const std::wstring& install_dir,
|
||||
const std::wstring& version)
|
||||
{
|
||||
std::wstring app_name_oneword = get_app_name_oneword();
|
||||
// Clears velopack's recently created 'uninstall' registry entry.
|
||||
// We are going to use a custom one.
|
||||
// Note that velopack doesn't know about our custom entry.
|
||||
std::wstring key_path = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + app_name_oneword;
|
||||
RegDeleteTreeW(HKEY_CURRENT_USER, key_path.c_str());
|
||||
// Use a unique key name to avoid conflicts with any existing NSIS-based uninstall info,
|
||||
// which can cause nly one of the two entries to show up in the Add/Remove Programs list.
|
||||
// which can cause only one of the two entries to show up in the Add/Remove Programs list.
|
||||
// The UI will show DisplayName, so the key name itself is not important to be user-friendly.
|
||||
std::wstring key_path = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vlpk" + app_name_oneword;
|
||||
key_path = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Vlpk" + app_name_oneword;
|
||||
HKEY hkey;
|
||||
|
||||
if (RegCreateKeyExW(HKEY_CURRENT_USER, key_path.c_str(), 0, NULL,
|
||||
@@ -532,7 +574,7 @@ static void register_uninstall_info(const std::wstring& install_dir,
|
||||
RegSetValueExW(hkey, L"URLInfoAbout", 0, REG_SZ,
|
||||
(BYTE*)link_url.c_str(), (DWORD)((link_url.size() + 1) * sizeof(wchar_t)));
|
||||
|
||||
link_url = L"http://secondlife.com/support/downloads/";
|
||||
link_url = L"https://secondlife.com/support/downloads/";
|
||||
RegSetValueExW(hkey, L"URLUpdateInfo", 0, REG_SZ,
|
||||
(BYTE*)link_url.c_str(), (DWORD)((link_url.size() + 1) * sizeof(wchar_t)));
|
||||
|
||||
@@ -540,7 +582,18 @@ static void register_uninstall_info(const std::wstring& install_dir,
|
||||
RegSetValueExW(hkey, L"NoModify", 0, REG_DWORD, (BYTE*)&no_modify, sizeof(DWORD));
|
||||
RegSetValueExW(hkey, L"NoRepair", 0, REG_DWORD, (BYTE*)&no_modify, sizeof(DWORD));
|
||||
|
||||
DWORD estimated_size = 120000;
|
||||
// Format YYYYMMDD
|
||||
wchar_t dateStr[9];
|
||||
time_t t = time(NULL);
|
||||
struct tm tm;
|
||||
localtime_s(&tm, &t);
|
||||
wcsftime(dateStr, 9, L"%Y%m%d", &tm);
|
||||
RegSetValueExW(hkey, L"InstallDate", 0, REG_SZ, (BYTE*)dateStr, (DWORD)((wcslen(dateStr) + 1) * sizeof(wchar_t))); // Let Windows fill in the install date
|
||||
|
||||
// 800 MB, inaccurate, but for a rough idea.
|
||||
// We can check folder size here, but it would take time and
|
||||
// information is of low importance.
|
||||
DWORD estimated_size = 800000;
|
||||
RegSetValueExW(hkey, L"EstimatedSize", 0, REG_DWORD, (BYTE*)&estimated_size, sizeof(DWORD));
|
||||
|
||||
RegCloseKey(hkey);
|
||||
@@ -579,19 +632,31 @@ static void remove_shortcuts(const std::wstring& app_name)
|
||||
DeleteFileW((desktop_path + L"\\" + app_name + L".lnk").c_str());
|
||||
}
|
||||
|
||||
static void on_first_run(void* p_user_data, const char* app_version)
|
||||
{
|
||||
// Velopack first executes 'after install' hook, then writes registry,
|
||||
// then executes 'on first run' hook.
|
||||
// As we need to clear velopack's 'uninstall' registry entry and use
|
||||
// our own, clean it here instead of on_after_install.
|
||||
|
||||
std::wstring install_dir = get_install_dir();
|
||||
std::wstring app_name = get_app_name();
|
||||
|
||||
int len = MultiByteToWideChar(CP_UTF8, 0, app_version, -1, NULL, 0);
|
||||
std::wstring version(len, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, app_version, -1, &version[0], len);
|
||||
|
||||
register_uninstall_info(install_dir, app_name, version);
|
||||
}
|
||||
|
||||
static void on_after_install(void* user_data, const char* app_version)
|
||||
{
|
||||
std::wstring install_dir = get_install_dir();
|
||||
std::wstring app_name = get_app_name();
|
||||
std::wstring exe_path = install_dir + L"\\" + get_viewer_exe_name();
|
||||
|
||||
int len = MultiByteToWideChar(CP_UTF8, 0, app_version, -1, NULL, 0);
|
||||
std::wstring version(len, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, app_version, -1, &version[0], len);
|
||||
|
||||
register_protocol_handler(PROTOCOL_SECONDLIFE, L"URL:Second Life", exe_path);
|
||||
register_protocol_handler(PROTOCOL_GRID_INFO, L"URL:Second Life", exe_path);
|
||||
register_uninstall_info(install_dir, app_name, version);
|
||||
create_shortcuts(install_dir, app_name);
|
||||
}
|
||||
|
||||
@@ -620,6 +685,10 @@ static void on_log_message(void* user_data, const char* level, const char* messa
|
||||
// TODO: Implement protocol handler registration via Launch Services
|
||||
// TODO: Implement app bundle management
|
||||
|
||||
static void on_first_run(void* user_data, const char* app_version)
|
||||
{
|
||||
}
|
||||
|
||||
static void on_after_install(void* user_data, const char* app_version)
|
||||
{
|
||||
// macOS handles protocol registration via Info.plist CFBundleURLTypes
|
||||
@@ -808,6 +877,7 @@ bool velopack_initialize()
|
||||
vpkc_app_set_auto_apply_on_startup(false);
|
||||
|
||||
#if LL_WINDOWS || LL_DARWIN
|
||||
vpkc_app_set_hook_first_run(on_first_run);
|
||||
vpkc_app_set_hook_after_install(on_after_install);
|
||||
vpkc_app_set_hook_before_uninstall(on_before_uninstall);
|
||||
#endif
|
||||
|
||||
@@ -46,7 +46,12 @@ void velopack_set_progress_callback(std::function<void(int)> callback);
|
||||
void velopack_cleanup();
|
||||
|
||||
#if LL_WINDOWS
|
||||
bool get_nsis_uninstaller_path(wchar_t* path_buffer, DWORD bufSize, S32 cur_major_ver, S32 cur_minor_ver, S32 cur_patch_ver, U64 cur_build_ver);
|
||||
void clear_nsis_links();
|
||||
bool get_nsis_version(
|
||||
int& nsis_major,
|
||||
int& nsis_minor,
|
||||
int& nsis_patch,
|
||||
uint64_t& nsis_build);
|
||||
#endif
|
||||
|
||||
#endif // LL_VELOPACK
|
||||
|
||||
@@ -202,17 +202,12 @@ No tutorial is currently available.
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="PromptRemoveNsisInstallation"
|
||||
name="FoundLegacyNsisInstallation"
|
||||
type="alertmodal">
|
||||
[APP_NAME] found an installation from an older version. Do you want to uninstall the previous version now?
|
||||
|
||||
The uninstaller may display additional prompts requesting permission to access or modify files on your disk.
|
||||
<tag>confirm </tag>
|
||||
<usetemplate
|
||||
ignoretext="Ask to remove legacy installation"
|
||||
name="okcancelignore"
|
||||
notext="Cancel"
|
||||
yestext="Uninstall"/>
|
||||
[APP_NAME] found an installation of an older version [VERSION]. To uninstall the older version, please follow [https://community.secondlife.com/knowledgebase/english/how-to-uninstall-and-reinstall-second-life-r524 this manual].
|
||||
<usetemplate
|
||||
name="okbutton"
|
||||
yestext="OK"/>
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
|
||||
@@ -658,21 +658,6 @@ class Windows_x86_64_Manifest(ViewerManifest):
|
||||
# '*.tar.xz')))
|
||||
# </FS:Ansariel>
|
||||
|
||||
# <FS:Ansariel> Remove VMP
|
||||
#with self.prefix(src=os.path.join(pkgdir, "VMP")):
|
||||
# include the compiled launcher scripts so that it gets included in the file_list
|
||||
# self.path('SLVersionChecker.exe')
|
||||
|
||||
#with self.prefix(dst="vmp_icons"):
|
||||
# with self.prefix(src=self.icon_path()):
|
||||
# self.path("secondlife.ico")
|
||||
#VMP Tkinter icons
|
||||
# with self.prefix(src="vmp_icons"):
|
||||
# self.path("*.png")
|
||||
# self.path("*.gif")
|
||||
|
||||
# </FS:Ansariel> Remove VMP
|
||||
|
||||
# Plugin host application
|
||||
self.path2basename(os.path.join(os.pardir,
|
||||
'llplugin', 'slplugin', self.args['configuration']),
|
||||
@@ -2002,6 +1987,12 @@ class Darwin_x86_64_Manifest(ViewerManifest):
|
||||
if self.args.get('velopack', 'OFF') == 'ON':
|
||||
self.velopack_package_finish()
|
||||
|
||||
# Generate Velopack update packages if enabled
|
||||
# This creates the nupkg and RELEASES files needed for auto-updates
|
||||
# Distribution is still via DMG, but updates use Velopack
|
||||
if self.args.get('velopack', 'OFF') == 'ON':
|
||||
self.velopack_package_finish()
|
||||
|
||||
def velopack_package_finish(self):
|
||||
"""Generate Velopack update packages for macOS.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user