mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-25 07:35:38 +00:00
Added an application updater that checks for new releases on startup.
This commit is contained in:
parent
43a18146d5
commit
270351b033
|
@ -32,20 +32,22 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMake/Utils
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/CMake/Packages)
|
${CMAKE_CURRENT_SOURCE_DIR}/CMake/Packages)
|
||||||
|
|
||||||
# Define the options.
|
# Define the options.
|
||||||
option(GL "Set to ON if targeting Desktop OpenGL" ${GL})
|
option(GL "Set to ON if targeting Desktop OpenGL" ON)
|
||||||
option(GLES "Set to ON if targeting OpenGL ES" ${GLES})
|
option(GLES "Set to ON if targeting OpenGL ES" OFF)
|
||||||
option(APPIMAGE_BUILD "Set to ON when building as an AppImage" ${APPIMAGE_BUILD})
|
option(APPLICATION_UPDATER "Set to OFF to build without the application updater" ON)
|
||||||
option(FLATPAK_BUILD "Set to ON when building as a Flatpak" ${FLATPAK_BUILD})
|
option(APPIMAGE_BUILD "Set to ON when building as an AppImage" OFF)
|
||||||
option(STEAM_DECK "Set to ON to enable a Valve Steam Deck specific build" ${STEAM_DECK})
|
option(AUR_BUILD "Set to ON when building for the AUR" OFF)
|
||||||
option(RETRODECK "Set to ON to enable a RetroDECK specific build" ${RETRODECK})
|
option(FLATPAK_BUILD "Set to ON when building as a Flatpak" OFF)
|
||||||
option(RPI "Set to ON to enable a Raspberry Pi specific build" ${RPI})
|
option(STEAM_DECK "Set to ON to enable a Valve Steam Deck specific build" OFF)
|
||||||
option(BUNDLED_CERTS "Set to ON to use bundled TLS/SSL certificates" ${BUNDLED_CERTS})
|
option(RETRODECK "Set to ON to enable a RetroDECK specific build" OFF)
|
||||||
option(CEC "Set to ON to enable CEC" ${CEC})
|
option(RPI "Set to ON to enable a Raspberry Pi specific build" OFF)
|
||||||
option(VIDEO_HW_DECODING "Set to ON to enable FFmpeg HW decoding" ${VIDEO_HW_DECODING})
|
option(BUNDLED_CERTS "Set to ON to use bundled TLS/SSL certificates" OFF)
|
||||||
option(CLANG_TIDY "Set to ON to build using the clang-tidy static analyzer" ${CLANG_TIDY})
|
option(CEC "Set to ON to enable CEC" OFF)
|
||||||
option(ASAN "Set to ON to build with AddressSanitizer" ${ASAN})
|
option(VIDEO_HW_DECODING "Set to ON to enable FFmpeg HW decoding" OFF)
|
||||||
option(TSAN "Set to ON to build with ThreadSanitizer" ${TSAN})
|
option(CLANG_TIDY "Set to ON to build using the clang-tidy static analyzer" OFF)
|
||||||
option(UBSAN "Set to ON to build with UndefinedBehaviorSanitizer" ${UBSAN})
|
option(ASAN "Set to ON to build with AddressSanitizer" OFF)
|
||||||
|
option(TSAN "Set to ON to build with ThreadSanitizer" OFF)
|
||||||
|
option(UBSAN "Set to ON to build with UndefinedBehaviorSanitizer" OFF)
|
||||||
|
|
||||||
if(CLANG_TIDY)
|
if(CLANG_TIDY)
|
||||||
find_program(CLANG_TIDY_BINARY NAMES clang-tidy)
|
find_program(CLANG_TIDY_BINARY NAMES clang-tidy)
|
||||||
|
@ -307,6 +309,10 @@ if(FLATPAK_BUILD)
|
||||||
message("-- Building as a Flatpak")
|
message("-- Building as a Flatpak")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(AUR_BUILD)
|
||||||
|
message("-- Building for the AUR")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(STEAM_DECK AND RETRODECK)
|
if(STEAM_DECK AND RETRODECK)
|
||||||
message(FATAL_ERROR "-- STEAM_DECK and RETRODECK can't be combined")
|
message(FATAL_ERROR "-- STEAM_DECK and RETRODECK can't be combined")
|
||||||
endif()
|
endif()
|
||||||
|
@ -339,13 +345,44 @@ if(VIDEO_HW_DECODING)
|
||||||
message("-- Building with FFmpeg HW decoding")
|
message("-- Building with FFmpeg HW decoding")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(AUR_BUILD OR FLATPAK_BUILD OR RETRODECK OR RPI)
|
||||||
|
set(APPLICATION_UPDATER OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_SYSTEM_NAME MATCHES FreeBSD OR CMAKE_SYSTEM_NAME MATCHES NetBSD OR CMAKE_SYSTEM_NAME MATCHES OpenBSD)
|
||||||
|
set(APPLICATION_UPDATER OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(APPLICATION_UPDATER)
|
||||||
|
add_compile_definitions(APPLICATION_UPDATER)
|
||||||
|
else()
|
||||||
|
message("-- Building without application updater")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# This is needed to identify the package type for the application updater.
|
||||||
|
if(CMAKE_SYSTEM_NAME MATCHES Linux)
|
||||||
|
if(LINUX_CPACK_GENERATOR MATCHES DEB)
|
||||||
|
add_compile_definitions(LINUX_DEB_PACKAGE)
|
||||||
|
elseif(LINUX_CPACK_GENERATOR MATCHES RPM)
|
||||||
|
add_compile_definitions(LINUX_RPM_PACKAGE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
if(CMAKE_SYSTEM_PROCESSOR MATCHES arm)
|
||||||
|
add_compile_definitions(MACOS_APPLE_CPU)
|
||||||
|
else()
|
||||||
|
add_compile_definitions(MACOS_INTEL_CPU)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
if(APPLE AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS 10.14)
|
if(APPLE AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS 10.14)
|
||||||
add_compile_definitions(LEGACY_MACOS)
|
add_compile_definitions(LEGACY_MACOS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# If it's an alpha, beta or dev build, then display the build date in the main menu.
|
# Affects the application updater and is used for displaying version info in the main menu.
|
||||||
if(ES_VERSION MATCHES alpha OR ES_VERSION MATCHES beta OR ES_VERSION MATCHES dev)
|
if(ES_VERSION MATCHES alpha OR ES_VERSION MATCHES beta OR ES_VERSION MATCHES dev)
|
||||||
add_compile_definitions(MENU_BUILD_DATE)
|
add_compile_definitions(IS_PRERELEASE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# GLM library options.
|
# GLM library options.
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
project(emulationstation-de)
|
project(emulationstation-de)
|
||||||
|
|
||||||
set(ES_HEADERS
|
set(ES_HEADERS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/ApplicationUpdater.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/CollectionSystemsManager.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/CollectionSystemsManager.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/EmulationStation.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/EmulationStation.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/FileData.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/FileData.h
|
||||||
|
@ -58,6 +59,7 @@ set(ES_HEADERS
|
||||||
)
|
)
|
||||||
|
|
||||||
set(ES_SOURCES
|
set(ES_SOURCES
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/ApplicationUpdater.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/CollectionSystemsManager.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/CollectionSystemsManager.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/FileData.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/FileData.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/FileFilterIndex.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/FileFilterIndex.cpp
|
||||||
|
|
403
es-app/src/ApplicationUpdater.cpp
Normal file
403
es-app/src/ApplicationUpdater.cpp
Normal file
|
@ -0,0 +1,403 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// EmulationStation Desktop Edition
|
||||||
|
// ApplicationUpdater.cpp
|
||||||
|
//
|
||||||
|
// Checks for application updates.
|
||||||
|
// In the future updates will also be downloaded and possibly installed.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "ApplicationUpdater.h"
|
||||||
|
|
||||||
|
#include "EmulationStation.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include "Settings.h"
|
||||||
|
#include "utils/StringUtil.h"
|
||||||
|
#include "utils/TimeUtil.h"
|
||||||
|
|
||||||
|
#include "rapidjson/document.h"
|
||||||
|
#include "rapidjson/error/en.h"
|
||||||
|
|
||||||
|
#include <SDL2/SDL_timer.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
#define MAX_DOWNLOAD_TIME 1
|
||||||
|
|
||||||
|
ApplicationUpdater::ApplicationUpdater()
|
||||||
|
: mTimer {0}
|
||||||
|
, mMaxTime {0}
|
||||||
|
, mAbortDownload {false}
|
||||||
|
, mCheckedForUpdate {false}
|
||||||
|
{
|
||||||
|
mUrl = "https://gitlab.com/api/v4/projects/18817634/repository/files/latest_release.json/"
|
||||||
|
"raw?ref=master";
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplicationUpdater::~ApplicationUpdater()
|
||||||
|
{
|
||||||
|
// This is needed if getResults() was never called.
|
||||||
|
if (mThread)
|
||||||
|
mThread->join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplicationUpdater::checkForUpdates()
|
||||||
|
{
|
||||||
|
const std::string updateFrequency {
|
||||||
|
Settings::getInstance()->getString("ApplicationUpdaterFrequency")};
|
||||||
|
if (updateFrequency == "never")
|
||||||
|
return;
|
||||||
|
|
||||||
|
const std::string lastCheck {Settings::getInstance()->getString("ApplicationUpdaterLastCheck")};
|
||||||
|
unsigned int frequencyDays {0};
|
||||||
|
bool checkForUpdate {false};
|
||||||
|
|
||||||
|
if (updateFrequency == "daily")
|
||||||
|
frequencyDays = 1;
|
||||||
|
else if (updateFrequency == "weekly")
|
||||||
|
frequencyDays = 7;
|
||||||
|
else if (updateFrequency == "monthly")
|
||||||
|
frequencyDays = 30;
|
||||||
|
|
||||||
|
// Frequency set to "always" or it's the first time we check for updates.
|
||||||
|
if (frequencyDays == 0 || lastCheck == "") {
|
||||||
|
checkForUpdate = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const Utils::Time::DateTime now {Utils::Time::now()};
|
||||||
|
const Utils::Time::DateTime lastTime {lastCheck};
|
||||||
|
const Utils::Time::Duration dur {now.getTime() - lastTime.getTime()};
|
||||||
|
if (dur.getDays() >= frequencyDays)
|
||||||
|
checkForUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkForUpdate) {
|
||||||
|
LOG(LogInfo) << "Checking for application updates...";
|
||||||
|
mThread = std::make_unique<std::thread>(&ApplicationUpdater::updaterThread, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplicationUpdater::updaterThread()
|
||||||
|
{
|
||||||
|
if (!downloadFile()) {
|
||||||
|
compareVersions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ApplicationUpdater::downloadFile()
|
||||||
|
{
|
||||||
|
const unsigned int startTime {SDL_GetTicks()};
|
||||||
|
mTimer = startTime;
|
||||||
|
mMaxTime = mTimer + (MAX_DOWNLOAD_TIME * 1000);
|
||||||
|
|
||||||
|
mStatus = ASYNC_IN_PROGRESS;
|
||||||
|
mRequest = std::unique_ptr<HttpReq>(std::make_unique<HttpReq>(mUrl));
|
||||||
|
|
||||||
|
while (mTimer < mMaxTime || !mAbortDownload) {
|
||||||
|
SDL_Delay(10);
|
||||||
|
try {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
catch (std::runtime_error& e) {
|
||||||
|
LOG(LogWarning) << "ApplicationUpdater: Couldn't download \"latest_release.json\": "
|
||||||
|
<< e.what();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (mStatus == ASYNC_DONE)
|
||||||
|
break;
|
||||||
|
mTimer = SDL_GetTicks();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (mStatus == ASYNC_DONE) {
|
||||||
|
rapidjson::Document doc;
|
||||||
|
const std::string& fileContents {mRequest->getContent()};
|
||||||
|
doc.Parse(&fileContents[0], fileContents.length());
|
||||||
|
if (doc.HasMember("error") && doc["error"].IsString()) {
|
||||||
|
LOG(LogWarning)
|
||||||
|
<< "ApplicationUpdater: Couldn't download \"latest_release.json\", received "
|
||||||
|
"server error response \""
|
||||||
|
<< doc["error"].GetString() << "\"";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
LOG(LogDebug)
|
||||||
|
<< "ApplicationUpdater::downloadFile(): Downloaded \"latest_release.json\" in "
|
||||||
|
<< mTimer - startTime << " milliseconds";
|
||||||
|
try {
|
||||||
|
parseFile();
|
||||||
|
}
|
||||||
|
catch (std::runtime_error& e) {
|
||||||
|
LOG(LogError) << "ApplicationUpdater: Couldn't parse \"latest_release.json\": "
|
||||||
|
<< e.what();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mAbortDownload) {
|
||||||
|
LOG(LogWarning) << "ApplicationUpdater: Aborted download of \"latest_release.json\" after "
|
||||||
|
<< mTimer - startTime << " milliseconds as the application has started up";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG(LogWarning) << "ApplicationUpdater: Couldn't download \"latest_release.json\" within "
|
||||||
|
<< MAX_DOWNLOAD_TIME << " second time limit";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplicationUpdater::update()
|
||||||
|
{
|
||||||
|
HttpReq::Status reqStatus {mRequest->status()};
|
||||||
|
if (reqStatus == HttpReq::REQ_SUCCESS) {
|
||||||
|
mStatus = ASYNC_DONE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not ready yet.
|
||||||
|
if (reqStatus == HttpReq::REQ_IN_PROGRESS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Everything else is some sort of error.
|
||||||
|
std::string errorMessage {"Network error (status: "};
|
||||||
|
errorMessage.append(std::to_string(reqStatus)).append(") - ").append(mRequest->getErrorMsg());
|
||||||
|
throw std::runtime_error(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplicationUpdater::parseFile()
|
||||||
|
{
|
||||||
|
assert(mRequest->status() == HttpReq::REQ_SUCCESS);
|
||||||
|
|
||||||
|
const std::string fileContents {mRequest->getContent()};
|
||||||
|
rapidjson::Document doc;
|
||||||
|
doc.Parse(&fileContents[0], fileContents.length());
|
||||||
|
|
||||||
|
if (doc.HasParseError())
|
||||||
|
throw std::runtime_error(rapidjson::GetParseError_En(doc.GetParseError()));
|
||||||
|
|
||||||
|
const std::vector<std::string> releaseTypes {"stable", "prerelease"};
|
||||||
|
|
||||||
|
for (auto& releaseType : releaseTypes) {
|
||||||
|
Release release;
|
||||||
|
if (doc.HasMember(releaseType.c_str())) {
|
||||||
|
release.releaseType = releaseType.c_str();
|
||||||
|
const rapidjson::Value& releaseTypeEntry {doc[releaseType.c_str()]};
|
||||||
|
|
||||||
|
if (releaseTypeEntry.HasMember("version") && releaseTypeEntry["version"].IsString())
|
||||||
|
release.version = releaseTypeEntry["version"].GetString();
|
||||||
|
else
|
||||||
|
throw std::runtime_error("Invalid file structure, \"version\" key missing");
|
||||||
|
|
||||||
|
// There may not be a prerelease available.
|
||||||
|
if (releaseType == "prerelease" && release.version == "")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (releaseTypeEntry.HasMember("release") && releaseTypeEntry["release"].IsString())
|
||||||
|
release.releaseNum = releaseTypeEntry["release"].GetString();
|
||||||
|
else
|
||||||
|
throw std::runtime_error("Invalid file structure, \"release\" key missing");
|
||||||
|
|
||||||
|
if (releaseTypeEntry.HasMember("date") && releaseTypeEntry["date"].IsString())
|
||||||
|
release.date = releaseTypeEntry["date"].GetString();
|
||||||
|
else
|
||||||
|
throw std::runtime_error("Invalid file structure, \"date\" key missing");
|
||||||
|
|
||||||
|
if (releaseTypeEntry.HasMember("packages") && releaseTypeEntry["packages"].IsArray()) {
|
||||||
|
const rapidjson::Value& packages {releaseTypeEntry["packages"]};
|
||||||
|
for (int i {0}; i < static_cast<int>(packages.Size()); ++i) {
|
||||||
|
Package package;
|
||||||
|
const rapidjson::Value& packageEntry {packages[i]};
|
||||||
|
|
||||||
|
if (packageEntry.HasMember("name") && packageEntry["name"].IsString())
|
||||||
|
package.name = packageEntry["name"].GetString();
|
||||||
|
else
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Invalid file structure, package \"name\" key missing");
|
||||||
|
|
||||||
|
if (packageEntry.HasMember("filename") && packageEntry["filename"].IsString())
|
||||||
|
package.filename = packageEntry["filename"].GetString();
|
||||||
|
else
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Invalid file structure, package \"filename\" key missing");
|
||||||
|
|
||||||
|
if (packageEntry.HasMember("url") && packageEntry["url"].IsString())
|
||||||
|
package.url = packageEntry["url"].GetString();
|
||||||
|
else
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Invalid file structure, package \"url\" key missing");
|
||||||
|
|
||||||
|
if (packageEntry.HasMember("md5") && packageEntry["md5"].IsString())
|
||||||
|
package.md5 = packageEntry["md5"].GetString();
|
||||||
|
else
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Invalid file structure, package \"md5\" key missing");
|
||||||
|
|
||||||
|
if (packageEntry.HasMember("message") && packageEntry["message"].IsString())
|
||||||
|
package.message = packageEntry["message"].GetString();
|
||||||
|
else
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Invalid file structure, package \"message\" key missing");
|
||||||
|
|
||||||
|
release.packages.emplace_back(package);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Invalid file structure");
|
||||||
|
}
|
||||||
|
if (releaseType == "stable")
|
||||||
|
mStableRelease = std::move(release);
|
||||||
|
else
|
||||||
|
mPrerelease = std::move(release);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Invalid file structure, release type \"" + releaseType +
|
||||||
|
"\" missing");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mPrerelease.version == "") {
|
||||||
|
LOG(LogDebug) << "ApplicationUpdater::parseFile(): Latest stable release is "
|
||||||
|
<< mStableRelease.version << " (r" << mStableRelease.releaseNum
|
||||||
|
<< "), no prerelease currently available";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG(LogDebug) << "ApplicationUpdater::parseFile(): Latest stable release is "
|
||||||
|
<< mStableRelease.version << " (r" << mStableRelease.releaseNum
|
||||||
|
<< ") and latest prerelease is " << mPrerelease.version << " (r"
|
||||||
|
<< mPrerelease.releaseNum << ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplicationUpdater::compareVersions()
|
||||||
|
{
|
||||||
|
std::deque<Release*> releaseTypes {&mStableRelease};
|
||||||
|
|
||||||
|
if (mPrerelease.version != "") {
|
||||||
|
#if defined(IS_PRERELEASE)
|
||||||
|
releaseTypes.emplace_front(&mPrerelease);
|
||||||
|
#else
|
||||||
|
if (Settings::getInstance()->getBool("ApplicationUpdaterPrereleases"))
|
||||||
|
releaseTypes.emplace_front(&mPrerelease);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& releaseType : releaseTypes) {
|
||||||
|
bool newVersion {false};
|
||||||
|
// If the version does not follow the semantic versioning scheme then always consider it to
|
||||||
|
// be a new release as perhaps the version scheme will be changed sometime in the future.
|
||||||
|
if (count_if(releaseType->version.cbegin(), releaseType->version.cend(),
|
||||||
|
[](char c) { return c == '.'; }) != 2) {
|
||||||
|
newVersion = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::vector<std::string> fileVersion {
|
||||||
|
Utils::String::delimitedStringToVector(releaseType->version, ".")};
|
||||||
|
|
||||||
|
const size_t dashPos {fileVersion.back().find('-')};
|
||||||
|
if (dashPos != std::string::npos)
|
||||||
|
fileVersion.back() = fileVersion.back().substr(0, dashPos);
|
||||||
|
|
||||||
|
int versionWeight {0};
|
||||||
|
|
||||||
|
if (std::stoi(fileVersion.at(0)) > PROGRAM_VERSION_MAJOR)
|
||||||
|
versionWeight += 8;
|
||||||
|
else if (std::stoi(fileVersion.at(0)) < PROGRAM_VERSION_MAJOR)
|
||||||
|
versionWeight -= 8;
|
||||||
|
|
||||||
|
if (std::stoi(fileVersion.at(1)) > PROGRAM_VERSION_MINOR)
|
||||||
|
versionWeight += 4;
|
||||||
|
else if (std::stoi(fileVersion.at(1)) < PROGRAM_VERSION_MINOR)
|
||||||
|
versionWeight -= 4;
|
||||||
|
|
||||||
|
if (std::stoi(fileVersion.at(2)) > PROGRAM_VERSION_MAINTENANCE)
|
||||||
|
versionWeight += 2;
|
||||||
|
else if (std::stoi(fileVersion.at(2)) < PROGRAM_VERSION_MAINTENANCE)
|
||||||
|
versionWeight -= 2;
|
||||||
|
|
||||||
|
// If versions match precisely then fall back to using the release number.
|
||||||
|
if (versionWeight == 0 && std::stoi(releaseType->releaseNum) > PROGRAM_RELEASE_NUMBER)
|
||||||
|
++versionWeight;
|
||||||
|
|
||||||
|
if (versionWeight > 0)
|
||||||
|
newVersion = true;
|
||||||
|
}
|
||||||
|
if (newVersion) {
|
||||||
|
std::string message;
|
||||||
|
|
||||||
|
for (auto& package : releaseType->packages) {
|
||||||
|
#if defined(_WIN64)
|
||||||
|
if (Settings::getInstance()->getBool("PortableMode")) {
|
||||||
|
if (package.name == "WindowsPortable")
|
||||||
|
message = package.message;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (package.name == "WindowsInstaller")
|
||||||
|
message = package.message;
|
||||||
|
}
|
||||||
|
#elif defined(MACOS_APPLE_CPU)
|
||||||
|
if (package.name == "macOSApple")
|
||||||
|
message = package.message;
|
||||||
|
#elif defined(MACOS_INTEL_CPU)
|
||||||
|
if (package.name == "macOSIntel")
|
||||||
|
message = package.message;
|
||||||
|
#elif defined(STEAM_DECK)
|
||||||
|
if (package.name == "LinuxSteamDeckAppImage")
|
||||||
|
message = package.message;
|
||||||
|
#elif defined(APPIMAGE_BUILD)
|
||||||
|
if (package.name == "LinuxAppImage")
|
||||||
|
message = package.message;
|
||||||
|
#elif defined(LINUX_DEB_PACKAGE)
|
||||||
|
if (package.name == "LinuxDEB")
|
||||||
|
message = package.message;
|
||||||
|
#elif defined(LINUX_RPM_PACKAGE)
|
||||||
|
if (package.name == "LinuxRPM")
|
||||||
|
message = package.message;
|
||||||
|
#endif
|
||||||
|
auto tempVar = package;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cut the message to 280 characters so we don't make the message box exceedingly large.
|
||||||
|
message = message.substr(0, 280);
|
||||||
|
|
||||||
|
LOG(LogInfo) << "ApplicationUpdater: A new "
|
||||||
|
<< (releaseType == &mStableRelease ? "stable release" : "prerelease")
|
||||||
|
<< " is available for download at https://es-de.org: "
|
||||||
|
<< releaseType->version << " (r" << releaseType->releaseNum
|
||||||
|
<< "), release date: " << releaseType->date;
|
||||||
|
|
||||||
|
mResults.append("New ")
|
||||||
|
.append(releaseType == &mStableRelease ? "release " : "prerelease ")
|
||||||
|
.append("available!\n")
|
||||||
|
.append(releaseType->version)
|
||||||
|
.append(" (")
|
||||||
|
.append(releaseType->date)
|
||||||
|
.append(")\n")
|
||||||
|
.append("can now be downloaded from\n")
|
||||||
|
.append("https://es-de.org/");
|
||||||
|
|
||||||
|
if (message != "")
|
||||||
|
mResults.append("\n").append(message);
|
||||||
|
|
||||||
|
mResults = Utils::String::toUpper(mResults);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mCheckedForUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplicationUpdater::getResults(std::string& results)
|
||||||
|
{
|
||||||
|
mAbortDownload = true;
|
||||||
|
|
||||||
|
if (mThread) {
|
||||||
|
mThread->join();
|
||||||
|
mThread.reset();
|
||||||
|
if (mCheckedForUpdate) {
|
||||||
|
if (mResults != "")
|
||||||
|
results = mResults;
|
||||||
|
Settings::getInstance()->setString(
|
||||||
|
"ApplicationUpdaterLastCheck",
|
||||||
|
Utils::Time::DateTime(Utils::Time::now()).getIsoString());
|
||||||
|
Settings::getInstance()->saveFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
es-app/src/ApplicationUpdater.h
Normal file
67
es-app/src/ApplicationUpdater.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// EmulationStation Desktop Edition
|
||||||
|
// ApplicationUpdater.h
|
||||||
|
//
|
||||||
|
// Checks for application updates.
|
||||||
|
// In the future updates will also be downloaded and possibly installed.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ES_APP_APPLICATION_UPDATER_H
|
||||||
|
#define ES_APP_APPLICATION_UPDATER_H
|
||||||
|
|
||||||
|
#include "AsyncHandle.h"
|
||||||
|
#include "HttpReq.h"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class ApplicationUpdater : public AsyncHandle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ApplicationUpdater();
|
||||||
|
~ApplicationUpdater();
|
||||||
|
|
||||||
|
void checkForUpdates();
|
||||||
|
void updaterThread();
|
||||||
|
bool downloadFile();
|
||||||
|
void update() override;
|
||||||
|
void parseFile();
|
||||||
|
void compareVersions();
|
||||||
|
void getResults(std::string& results);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Package {
|
||||||
|
std::string name;
|
||||||
|
std::string filename;
|
||||||
|
std::string url;
|
||||||
|
std::string md5;
|
||||||
|
std::string message;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Release {
|
||||||
|
std::string releaseType;
|
||||||
|
std::string version;
|
||||||
|
std::string releaseNum;
|
||||||
|
std::string date;
|
||||||
|
std::vector<Package> packages;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string mUrl;
|
||||||
|
std::string mResults;
|
||||||
|
unsigned int mTimer;
|
||||||
|
unsigned int mMaxTime;
|
||||||
|
std::atomic<bool> mAbortDownload;
|
||||||
|
bool mCheckedForUpdate;
|
||||||
|
|
||||||
|
std::unique_ptr<std::thread> mThread;
|
||||||
|
std::unique_ptr<HttpReq> mRequest;
|
||||||
|
AsyncHandleStatus mStatus;
|
||||||
|
|
||||||
|
Release mStableRelease;
|
||||||
|
Release mPrerelease;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ES_APP_APPLICATION_UPDATER_H
|
|
@ -1408,6 +1408,48 @@ void GuiMenu::openOtherOptions()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#if defined(APPLICATION_UPDATER)
|
||||||
|
// Application updater frequency.
|
||||||
|
auto applicationUpdaterFrequency = std::make_shared<OptionListComponent<std::string>>(
|
||||||
|
getHelpStyle(), "APPLICATION UPDATES", false);
|
||||||
|
const std::string& selectedUpdaterFrequency {
|
||||||
|
Settings::getInstance()->getString("ApplicationUpdaterFrequency")};
|
||||||
|
applicationUpdaterFrequency->add("ALWAYS", "always", selectedUpdaterFrequency == "always");
|
||||||
|
applicationUpdaterFrequency->add("DAILY", "daily", selectedUpdaterFrequency == "daily");
|
||||||
|
applicationUpdaterFrequency->add("WEEKLY", "weekly", selectedUpdaterFrequency == "weekly");
|
||||||
|
applicationUpdaterFrequency->add("MONTHLY", "monthly", selectedUpdaterFrequency == "monthly");
|
||||||
|
applicationUpdaterFrequency->add("NEVER", "never", selectedUpdaterFrequency == "never");
|
||||||
|
// If there are no objects returned, then there must be a manually modified entry in the
|
||||||
|
// configuration file. Simply set updater frequency to "always" in this case.
|
||||||
|
if (applicationUpdaterFrequency->getSelectedObjects().size() == 0)
|
||||||
|
applicationUpdaterFrequency->selectEntry(0);
|
||||||
|
s->addWithLabel("CHECK FOR APPLICATION UPDATES", applicationUpdaterFrequency);
|
||||||
|
s->addSaveFunc([applicationUpdaterFrequency, s] {
|
||||||
|
if (applicationUpdaterFrequency->getSelected() !=
|
||||||
|
Settings::getInstance()->getString("ApplicationUpdaterFrequency")) {
|
||||||
|
Settings::getInstance()->setString("ApplicationUpdaterFrequency",
|
||||||
|
applicationUpdaterFrequency->getSelected());
|
||||||
|
s->setNeedsSaving();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(APPLICATION_UPDATER) && !defined(IS_PRERELEASE)
|
||||||
|
// Whether to include prereleases when checking for application updates.
|
||||||
|
auto applicationUpdaterPrereleases = std::make_shared<SwitchComponent>();
|
||||||
|
applicationUpdaterPrereleases->setState(
|
||||||
|
Settings::getInstance()->getBool("ApplicationUpdaterPrereleases"));
|
||||||
|
s->addWithLabel("INCLUDE PRERELEASES IN UPDATE CHECKS", applicationUpdaterPrereleases);
|
||||||
|
s->addSaveFunc([applicationUpdaterPrereleases, s] {
|
||||||
|
if (applicationUpdaterPrereleases->getState() !=
|
||||||
|
Settings::getInstance()->getBool("ApplicationUpdaterPrereleases")) {
|
||||||
|
Settings::getInstance()->setBool("ApplicationUpdaterPrereleases",
|
||||||
|
applicationUpdaterPrereleases->getState());
|
||||||
|
s->setNeedsSaving();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
// Hide taskbar during the program session.
|
// Hide taskbar during the program session.
|
||||||
auto hide_taskbar = std::make_shared<SwitchComponent>();
|
auto hide_taskbar = std::make_shared<SwitchComponent>();
|
||||||
|
@ -1591,6 +1633,29 @@ void GuiMenu::openOtherOptions()
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(APPLICATION_UPDATER) && !defined(IS_PRERELEASE)
|
||||||
|
auto applicationUpdaterFrequencyFunc = [applicationUpdaterFrequency,
|
||||||
|
applicationUpdaterPrereleases](const std::string&) {
|
||||||
|
if (applicationUpdaterFrequency->getSelected() == "never") {
|
||||||
|
applicationUpdaterPrereleases->setEnabled(false);
|
||||||
|
applicationUpdaterPrereleases->setOpacity(DISABLED_OPACITY);
|
||||||
|
applicationUpdaterPrereleases->getParent()
|
||||||
|
->getChild(applicationUpdaterPrereleases->getChildIndex() - 1)
|
||||||
|
->setOpacity(DISABLED_OPACITY);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
applicationUpdaterPrereleases->setEnabled(true);
|
||||||
|
applicationUpdaterPrereleases->setOpacity(1.0f);
|
||||||
|
applicationUpdaterPrereleases->getParent()
|
||||||
|
->getChild(applicationUpdaterPrereleases->getChildIndex() - 1)
|
||||||
|
->setOpacity(1.0f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
applicationUpdaterFrequencyFunc(std::string());
|
||||||
|
applicationUpdaterFrequency->setCallback(applicationUpdaterFrequencyFunc);
|
||||||
|
#endif
|
||||||
|
|
||||||
s->setSize(mSize);
|
s->setSize(mSize);
|
||||||
mWindow->pushGui(s);
|
mWindow->pushGui(s);
|
||||||
}
|
}
|
||||||
|
@ -1673,7 +1738,7 @@ void GuiMenu::addVersionInfo()
|
||||||
mVersion.setFont(Font::get(FONT_SIZE_SMALL));
|
mVersion.setFont(Font::get(FONT_SIZE_SMALL));
|
||||||
mVersion.setColor(0x5E5E5EFF);
|
mVersion.setColor(0x5E5E5EFF);
|
||||||
|
|
||||||
#if defined(MENU_BUILD_DATE)
|
#if defined(IS_PRERELEASE)
|
||||||
mVersion.setText("EMULATIONSTATION-DE V" + Utils::String::toUpper(PROGRAM_VERSION_STRING) +
|
mVersion.setText("EMULATIONSTATION-DE V" + Utils::String::toUpper(PROGRAM_VERSION_STRING) +
|
||||||
" (Built " + __DATE__ + ")");
|
" (Built " + __DATE__ + ")");
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
// environment and starts listening to SDL events.
|
// environment and starts listening to SDL events.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include "ApplicationUpdater.h"
|
||||||
#include "AudioManager.h"
|
#include "AudioManager.h"
|
||||||
#include "CollectionSystemsManager.h"
|
#include "CollectionSystemsManager.h"
|
||||||
#include "EmulationStation.h"
|
#include "EmulationStation.h"
|
||||||
|
@ -62,6 +63,9 @@ namespace
|
||||||
Window* window {nullptr};
|
Window* window {nullptr};
|
||||||
int lastTime {0};
|
int lastTime {0};
|
||||||
|
|
||||||
|
#if defined(APPLICATION_UPDATER)
|
||||||
|
bool noUpdateCheck {false};
|
||||||
|
#endif
|
||||||
bool forceInputConfig {false};
|
bool forceInputConfig {false};
|
||||||
bool createSystemDirectories {false};
|
bool createSystemDirectories {false};
|
||||||
bool settingsNeedSaving {false};
|
bool settingsNeedSaving {false};
|
||||||
|
@ -361,6 +365,11 @@ bool parseArgs(int argc, char* argv[])
|
||||||
else if (strcmp(argv[i], "--no-splash") == 0) {
|
else if (strcmp(argv[i], "--no-splash") == 0) {
|
||||||
Settings::getInstance()->setBool("SplashScreen", false);
|
Settings::getInstance()->setBool("SplashScreen", false);
|
||||||
}
|
}
|
||||||
|
#if defined(APPLICATION_UPDATER)
|
||||||
|
else if (strcmp(argv[i], "--no-update-check") == 0) {
|
||||||
|
noUpdateCheck = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
else if (strcmp(argv[i], "--gamelist-only") == 0) {
|
else if (strcmp(argv[i], "--gamelist-only") == 0) {
|
||||||
Settings::getInstance()->setBool("ParseGamelistOnly", true);
|
Settings::getInstance()->setBool("ParseGamelistOnly", true);
|
||||||
settingsNeedSaving = true;
|
settingsNeedSaving = true;
|
||||||
|
@ -418,6 +427,9 @@ bool parseArgs(int argc, char* argv[])
|
||||||
" --anti-aliasing [0, 2 or 4] Set MSAA anti-aliasing to disabled, 2x or 4x\n"
|
" --anti-aliasing [0, 2 or 4] Set MSAA anti-aliasing to disabled, 2x or 4x\n"
|
||||||
#endif
|
#endif
|
||||||
" --no-splash Don't show the splash screen during startup\n"
|
" --no-splash Don't show the splash screen during startup\n"
|
||||||
|
#if defined(APPLICATION_UPDATER)
|
||||||
|
" --no-update-check Don't check for application updates during startup\n"
|
||||||
|
#endif
|
||||||
" --gamelist-only Skip automatic game ROM search, only read from gamelist.xml\n"
|
" --gamelist-only Skip automatic game ROM search, only read from gamelist.xml\n"
|
||||||
" --ignore-gamelist Ignore the gamelist.xml files\n"
|
" --ignore-gamelist Ignore the gamelist.xml files\n"
|
||||||
" --show-hidden-files Show hidden files and folders\n"
|
" --show-hidden-files Show hidden files and folders\n"
|
||||||
|
@ -587,6 +599,10 @@ int main(int argc, char* argv[])
|
||||||
<< PROGRAM_RELEASE_NUMBER << "), built " << PROGRAM_BUILT_STRING;
|
<< PROGRAM_RELEASE_NUMBER << "), built " << PROGRAM_BUILT_STRING;
|
||||||
if (portableMode) {
|
if (portableMode) {
|
||||||
LOG(LogInfo) << "Running in portable mode";
|
LOG(LogInfo) << "Running in portable mode";
|
||||||
|
Settings::getInstance()->setBool("PortableMode", true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Settings::getInstance()->setBool("PortableMode", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always close the log on exit.
|
// Always close the log on exit.
|
||||||
|
@ -676,6 +692,15 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
renderer = Renderer::getInstance();
|
renderer = Renderer::getInstance();
|
||||||
window = Window::getInstance();
|
window = Window::getInstance();
|
||||||
|
|
||||||
|
#if defined(APPLICATION_UPDATER)
|
||||||
|
std::unique_ptr<ApplicationUpdater> applicationUpdater;
|
||||||
|
if (!noUpdateCheck) {
|
||||||
|
applicationUpdater = std::make_unique<ApplicationUpdater>();
|
||||||
|
applicationUpdater->checkForUpdates();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ViewController::getInstance();
|
ViewController::getInstance();
|
||||||
CollectionSystemsManager::getInstance();
|
CollectionSystemsManager::getInstance();
|
||||||
Screensaver screensaver;
|
Screensaver screensaver;
|
||||||
|
@ -743,9 +768,14 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SystemData::sStartupExitSignal) {
|
if (!SystemData::sStartupExitSignal) {
|
||||||
if (loadSystemsStatus == loadSystemsReturnCode::LOADING_OK)
|
std::string updaterResults;
|
||||||
|
if (loadSystemsStatus == loadSystemsReturnCode::LOADING_OK) {
|
||||||
ThemeData::themeLoadedLogOutput();
|
ThemeData::themeLoadedLogOutput();
|
||||||
|
#if defined(APPLICATION_UPDATER)
|
||||||
|
if (!noUpdateCheck)
|
||||||
|
applicationUpdater->getResults(updaterResults);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
// Open the input configuration GUI if the force flag was passed from the command line.
|
// Open the input configuration GUI if the force flag was passed from the command line.
|
||||||
if (!loadSystemsStatus) {
|
if (!loadSystemsStatus) {
|
||||||
if (forceInputConfig) {
|
if (forceInputConfig) {
|
||||||
|
@ -762,12 +792,22 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
lastTime = SDL_GetTicks();
|
lastTime = SDL_GetTicks();
|
||||||
|
|
||||||
|
#if defined(APPLICATION_UPDATER)
|
||||||
|
if (!noUpdateCheck)
|
||||||
|
applicationUpdater.reset();
|
||||||
|
#endif
|
||||||
|
|
||||||
LOG(LogInfo) << "Application startup time: "
|
LOG(LogInfo) << "Application startup time: "
|
||||||
<< std::chrono::duration_cast<std::chrono::milliseconds>(
|
<< std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
std::chrono::system_clock::now() - applicationStartTime)
|
std::chrono::system_clock::now() - applicationStartTime)
|
||||||
.count()
|
.count()
|
||||||
<< " ms";
|
<< " ms";
|
||||||
|
|
||||||
|
#if defined(APPLICATION_UPDATER)
|
||||||
|
if (updaterResults != "")
|
||||||
|
ViewController::getInstance()->updateAvailableDialog(updaterResults);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Main application loop.
|
// Main application loop.
|
||||||
|
|
||||||
if (!SystemData::sStartupExitSignal) {
|
if (!SystemData::sStartupExitSignal) {
|
||||||
|
|
|
@ -208,6 +208,15 @@ void ViewController::invalidAlternativeEmulatorDialog()
|
||||||
"INTERFACE IN THE 'OTHER SETTINGS' MENU"));
|
"INTERFACE IN THE 'OTHER SETTINGS' MENU"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ViewController::updateAvailableDialog(const std::string& message)
|
||||||
|
{
|
||||||
|
mWindow->pushGui(new GuiMsgBox(getHelpStyle(), message, "OK", nullptr, "", nullptr, "", nullptr,
|
||||||
|
true, true,
|
||||||
|
(mRenderer->getIsVerticalOrientation() ?
|
||||||
|
0.85f :
|
||||||
|
0.45f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
||||||
|
}
|
||||||
|
|
||||||
void ViewController::goToStart(bool playTransition)
|
void ViewController::goToStart(bool playTransition)
|
||||||
{
|
{
|
||||||
// Needed to avoid segfaults during emergency shutdown.
|
// Needed to avoid segfaults during emergency shutdown.
|
||||||
|
|
|
@ -36,6 +36,7 @@ public:
|
||||||
void invalidSystemsFileDialog();
|
void invalidSystemsFileDialog();
|
||||||
void noGamesDialog();
|
void noGamesDialog();
|
||||||
void invalidAlternativeEmulatorDialog();
|
void invalidAlternativeEmulatorDialog();
|
||||||
|
void updateAvailableDialog(const std::string& message);
|
||||||
|
|
||||||
// Try to completely populate the GamelistView map.
|
// Try to completely populate the GamelistView map.
|
||||||
// Caches things so there's no pauses during transitions.
|
// Caches things so there's no pauses during transitions.
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
// HTTP request functions.
|
// HTTP request functions.
|
||||||
// Used by Scraper, GamesDBJSONScraper, GamesDBJSONScraperResources and
|
// Used by Scraper, GamesDBJSONScraper, GamesDBJSONScraperResources and
|
||||||
// ScreenScraper to download game information and media files.
|
// ScreenScraper to download game information and media files.
|
||||||
|
// Also used by ApplicationUpdater to check for application updates.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "HttpReq.h"
|
#include "HttpReq.h"
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
// HTTP request functions.
|
// HTTP request functions.
|
||||||
// Used by Scraper, GamesDBJSONScraper, GamesDBJSONScraperResources and
|
// Used by Scraper, GamesDBJSONScraper, GamesDBJSONScraperResources and
|
||||||
// ScreenScraper to download game information and media files.
|
// ScreenScraper to download game information and media files.
|
||||||
|
// Also used by ApplicationUpdater to check for application updates.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef ES_CORE_HTTP_REQ_H
|
#ifndef ES_CORE_HTTP_REQ_H
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
//
|
//
|
||||||
// Functions to read from and write to the configuration file es_settings.xml.
|
// Functions to read from and write to the configuration file es_settings.xml.
|
||||||
// The default values for the application settings are defined here as well.
|
// The default values for the application settings are defined here as well.
|
||||||
|
// This class is not thread safe.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
|
@ -40,6 +41,7 @@ namespace
|
||||||
"Debug", // --debug
|
"Debug", // --debug
|
||||||
|
|
||||||
// These options are only used internally during the application session:
|
// These options are only used internally during the application session:
|
||||||
|
"PortableMode",
|
||||||
"DebugGrid",
|
"DebugGrid",
|
||||||
"DebugText",
|
"DebugText",
|
||||||
"DebugImage",
|
"DebugImage",
|
||||||
|
@ -253,6 +255,8 @@ void Settings::setDefaults()
|
||||||
mStringMap["KeyboardQuitShortcut"] = {"AltF4", "AltF4"};
|
mStringMap["KeyboardQuitShortcut"] = {"AltF4", "AltF4"};
|
||||||
#endif
|
#endif
|
||||||
mStringMap["SaveGamelistsMode"] = {"always", "always"};
|
mStringMap["SaveGamelistsMode"] = {"always", "always"};
|
||||||
|
mStringMap["ApplicationUpdaterFrequency"] = {"always", "always"};
|
||||||
|
mBoolMap["ApplicationUpdaterPrereleases"] = {false, false};
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
mBoolMap["HideTaskbar"] = {false, false};
|
mBoolMap["HideTaskbar"] = {false, false};
|
||||||
#endif
|
#endif
|
||||||
|
@ -322,6 +326,8 @@ void Settings::setDefaults()
|
||||||
//
|
//
|
||||||
|
|
||||||
mStringMap["ApplicationVersion"] = {"", ""};
|
mStringMap["ApplicationVersion"] = {"", ""};
|
||||||
|
mStringMap["ApplicationUpdaterLastCheck"] = {"", ""};
|
||||||
|
mBoolMap["PortableMode"] = {false, false};
|
||||||
mBoolMap["DebugGrid"] = {false, false};
|
mBoolMap["DebugGrid"] = {false, false};
|
||||||
mBoolMap["DebugText"] = {false, false};
|
mBoolMap["DebugText"] = {false, false};
|
||||||
mBoolMap["DebugImage"] = {false, false};
|
mBoolMap["DebugImage"] = {false, false};
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
//
|
//
|
||||||
// Functions to read from and write to the configuration file es_settings.xml.
|
// Functions to read from and write to the configuration file es_settings.xml.
|
||||||
// The default values for the application settings are defined here as well.
|
// The default values for the application settings are defined here as well.
|
||||||
|
// This class is not thread safe.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef ES_CORE_SETTINGS_H
|
#ifndef ES_CORE_SETTINGS_H
|
||||||
|
|
Loading…
Reference in a new issue