mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2025-04-29 22:24:26 +02:00
Console colors and log invocation location (#3654)
This commit is contained in:
commit
0e00c28450
@ -125,6 +125,7 @@
|
|||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
#include <LocalPeer.h>
|
#include <LocalPeer.h>
|
||||||
|
|
||||||
|
#include <QStringLiteral>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys.h>
|
#include <sys.h>
|
||||||
#include "SysInfo.h"
|
#include "SysInfo.h"
|
||||||
@ -153,11 +154,16 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <QStyleHints>
|
#include <QStyleHints>
|
||||||
#include "WindowsConsole.h"
|
#include "console/WindowsConsole.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "console/Console.h"
|
||||||
|
|
||||||
#define STRINGIFY(x) #x
|
#define STRINGIFY(x) #x
|
||||||
#define TOSTRING(x) STRINGIFY(x)
|
#define TOSTRING(x) STRINGIFY(x)
|
||||||
|
|
||||||
@ -165,6 +171,63 @@ static const QLatin1String liveCheckFile("live.check");
|
|||||||
|
|
||||||
PixmapCache* PixmapCache::s_instance = nullptr;
|
PixmapCache* PixmapCache::s_instance = nullptr;
|
||||||
|
|
||||||
|
static bool isANSIColorConsole;
|
||||||
|
|
||||||
|
static QString defaultLogFormat = QStringLiteral(
|
||||||
|
"%{time process}"
|
||||||
|
" "
|
||||||
|
"%{if-debug}Debug:%{endif}"
|
||||||
|
"%{if-info}Info:%{endif}"
|
||||||
|
"%{if-warning}Warning:%{endif}"
|
||||||
|
"%{if-critical}Critical:%{endif}"
|
||||||
|
"%{if-fatal}Fatal:%{endif}"
|
||||||
|
" "
|
||||||
|
"%{if-category}[%{category}] %{endif}"
|
||||||
|
"%{message}"
|
||||||
|
" "
|
||||||
|
"(%{function}:%{line})");
|
||||||
|
|
||||||
|
#define ansi_reset "\x1b[0m"
|
||||||
|
#define ansi_bold "\x1b[1m"
|
||||||
|
#define ansi_reset_bold "\x1b[22m"
|
||||||
|
#define ansi_faint "\x1b[2m"
|
||||||
|
#define ansi_italic "\x1b[3m"
|
||||||
|
#define ansi_red_fg "\x1b[31m"
|
||||||
|
#define ansi_green_fg "\x1b[32m"
|
||||||
|
#define ansi_yellow_fg "\x1b[33m"
|
||||||
|
#define ansi_blue_fg "\x1b[34m"
|
||||||
|
#define ansi_purple_fg "\x1b[35m"
|
||||||
|
#define ansi_inverse "\x1b[7m"
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
static QString ansiLogFormat = QStringLiteral(
|
||||||
|
ansi_faint "%{time process}" ansi_reset
|
||||||
|
" "
|
||||||
|
"%{if-debug}" ansi_bold ansi_green_fg "D:" ansi_reset "%{endif}"
|
||||||
|
"%{if-info}" ansi_bold ansi_blue_fg "I:" ansi_reset "%{endif}"
|
||||||
|
"%{if-warning}" ansi_bold ansi_yellow_fg "W:" ansi_reset_bold "%{endif}"
|
||||||
|
"%{if-critical}" ansi_bold ansi_red_fg "C:" ansi_reset_bold "%{endif}"
|
||||||
|
"%{if-fatal}" ansi_bold ansi_inverse ansi_red_fg "F:" ansi_reset_bold "%{endif}"
|
||||||
|
" "
|
||||||
|
"%{if-category}" ansi_bold "[%{category}]" ansi_reset_bold " %{endif}"
|
||||||
|
"%{message}"
|
||||||
|
" "
|
||||||
|
ansi_reset ansi_faint "(%{function}:%{line})" ansi_reset
|
||||||
|
);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#undef ansi_inverse
|
||||||
|
#undef ansi_purple_fg
|
||||||
|
#undef ansi_blue_fg
|
||||||
|
#undef ansi_yellow_fg
|
||||||
|
#undef ansi_green_fg
|
||||||
|
#undef ansi_red_fg
|
||||||
|
#undef ansi_italic
|
||||||
|
#undef ansi_faint
|
||||||
|
#undef ansi_bold
|
||||||
|
#undef ansi_reset_bold
|
||||||
|
#undef ansi_reset
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/** This is used so that we can output to the log file in addition to the CLI. */
|
/** This is used so that we can output to the log file in addition to the CLI. */
|
||||||
@ -173,11 +236,24 @@ void appDebugOutput(QtMsgType type, const QMessageLogContext& context, const QSt
|
|||||||
static std::mutex loggerMutex;
|
static std::mutex loggerMutex;
|
||||||
const std::lock_guard<std::mutex> lock(loggerMutex); // synchronized, QFile logFile is not thread-safe
|
const std::lock_guard<std::mutex> lock(loggerMutex); // synchronized, QFile logFile is not thread-safe
|
||||||
|
|
||||||
|
if (isANSIColorConsole) {
|
||||||
|
// ensure default is set for log file
|
||||||
|
qSetMessagePattern(defaultLogFormat);
|
||||||
|
}
|
||||||
|
|
||||||
QString out = qFormatLogMessage(type, context, msg);
|
QString out = qFormatLogMessage(type, context, msg);
|
||||||
out += QChar::LineFeed;
|
out += QChar::LineFeed;
|
||||||
|
|
||||||
APPLICATION->logFile->write(out.toUtf8());
|
APPLICATION->logFile->write(out.toUtf8());
|
||||||
APPLICATION->logFile->flush();
|
APPLICATION->logFile->flush();
|
||||||
|
|
||||||
|
if (isANSIColorConsole) {
|
||||||
|
// format ansi for console;
|
||||||
|
qSetMessagePattern(ansiLogFormat);
|
||||||
|
out = qFormatLogMessage(type, context, msg);
|
||||||
|
out += QChar::LineFeed;
|
||||||
|
}
|
||||||
|
|
||||||
QTextStream(stderr) << out.toLocal8Bit();
|
QTextStream(stderr) << out.toLocal8Bit();
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
}
|
}
|
||||||
@ -218,8 +294,18 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
// attach the parent console if stdout not already captured
|
// attach the parent console if stdout not already captured
|
||||||
if (AttachWindowsConsole()) {
|
if (AttachWindowsConsole()) {
|
||||||
consoleAttached = true;
|
consoleAttached = true;
|
||||||
|
if (auto err = EnableAnsiSupport(); !err) {
|
||||||
|
isANSIColorConsole = true;
|
||||||
|
} else {
|
||||||
|
std::cout << "Error setting up ansi console" << err.message() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (console::isConsole()) {
|
||||||
|
isANSIColorConsole = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
setOrganizationName(BuildConfig.LAUNCHER_NAME);
|
setOrganizationName(BuildConfig.LAUNCHER_NAME);
|
||||||
setOrganizationDomain(BuildConfig.LAUNCHER_DOMAIN);
|
setOrganizationDomain(BuildConfig.LAUNCHER_DOMAIN);
|
||||||
setApplicationName(BuildConfig.LAUNCHER_NAME);
|
setApplicationName(BuildConfig.LAUNCHER_NAME);
|
||||||
@ -448,27 +534,14 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
qInstallMessageHandler(appDebugOutput);
|
qInstallMessageHandler(appDebugOutput);
|
||||||
|
qSetMessagePattern(defaultLogFormat);
|
||||||
qSetMessagePattern(
|
|
||||||
"%{time process}"
|
|
||||||
" "
|
|
||||||
"%{if-debug}D%{endif}"
|
|
||||||
"%{if-info}I%{endif}"
|
|
||||||
"%{if-warning}W%{endif}"
|
|
||||||
"%{if-critical}C%{endif}"
|
|
||||||
"%{if-fatal}F%{endif}"
|
|
||||||
" "
|
|
||||||
"|"
|
|
||||||
" "
|
|
||||||
"%{if-category}[%{category}]: %{endif}"
|
|
||||||
"%{message}");
|
|
||||||
|
|
||||||
bool foundLoggingRules = false;
|
bool foundLoggingRules = false;
|
||||||
|
|
||||||
auto logRulesFile = QStringLiteral("qtlogging.ini");
|
auto logRulesFile = QStringLiteral("qtlogging.ini");
|
||||||
auto logRulesPath = FS::PathCombine(dataPath, logRulesFile);
|
auto logRulesPath = FS::PathCombine(dataPath, logRulesFile);
|
||||||
|
|
||||||
qDebug() << "Testing" << logRulesPath << "...";
|
qInfo() << "Testing" << logRulesPath << "...";
|
||||||
foundLoggingRules = QFile::exists(logRulesPath);
|
foundLoggingRules = QFile::exists(logRulesPath);
|
||||||
|
|
||||||
// search the dataPath()
|
// search the dataPath()
|
||||||
@ -476,7 +549,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
if (!foundLoggingRules && !isPortable() && dirParam.isEmpty() && dataDirEnv.isEmpty()) {
|
if (!foundLoggingRules && !isPortable() && dirParam.isEmpty() && dataDirEnv.isEmpty()) {
|
||||||
logRulesPath = QStandardPaths::locate(QStandardPaths::AppDataLocation, FS::PathCombine("..", logRulesFile));
|
logRulesPath = QStandardPaths::locate(QStandardPaths::AppDataLocation, FS::PathCombine("..", logRulesFile));
|
||||||
if (!logRulesPath.isEmpty()) {
|
if (!logRulesPath.isEmpty()) {
|
||||||
qDebug() << "Found" << logRulesPath << "...";
|
qInfo() << "Found" << logRulesPath << "...";
|
||||||
foundLoggingRules = true;
|
foundLoggingRules = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -487,28 +560,28 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
#else
|
#else
|
||||||
logRulesPath = FS::PathCombine(m_rootPath, logRulesFile);
|
logRulesPath = FS::PathCombine(m_rootPath, logRulesFile);
|
||||||
#endif
|
#endif
|
||||||
qDebug() << "Testing" << logRulesPath << "...";
|
qInfo() << "Testing" << logRulesPath << "...";
|
||||||
foundLoggingRules = QFile::exists(logRulesPath);
|
foundLoggingRules = QFile::exists(logRulesPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (foundLoggingRules) {
|
if (foundLoggingRules) {
|
||||||
// load and set logging rules
|
// load and set logging rules
|
||||||
qDebug() << "Loading logging rules from:" << logRulesPath;
|
qInfo() << "Loading logging rules from:" << logRulesPath;
|
||||||
QSettings loggingRules(logRulesPath, QSettings::IniFormat);
|
QSettings loggingRules(logRulesPath, QSettings::IniFormat);
|
||||||
loggingRules.beginGroup("Rules");
|
loggingRules.beginGroup("Rules");
|
||||||
QStringList rule_names = loggingRules.childKeys();
|
QStringList rule_names = loggingRules.childKeys();
|
||||||
QStringList rules;
|
QStringList rules;
|
||||||
qDebug() << "Setting log rules:";
|
qInfo() << "Setting log rules:";
|
||||||
for (auto rule_name : rule_names) {
|
for (auto rule_name : rule_names) {
|
||||||
auto rule = QString("%1=%2").arg(rule_name).arg(loggingRules.value(rule_name).toString());
|
auto rule = QString("%1=%2").arg(rule_name).arg(loggingRules.value(rule_name).toString());
|
||||||
rules.append(rule);
|
rules.append(rule);
|
||||||
qDebug() << " " << rule;
|
qInfo() << " " << rule;
|
||||||
}
|
}
|
||||||
auto rules_str = rules.join("\n");
|
auto rules_str = rules.join("\n");
|
||||||
QLoggingCategory::setFilterRules(rules_str);
|
QLoggingCategory::setFilterRules(rules_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "<> Log initialized.";
|
qInfo() << "<> Log initialized.";
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -525,33 +598,33 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
qDebug() << qPrintable(BuildConfig.LAUNCHER_DISPLAYNAME + ", " + QString(BuildConfig.LAUNCHER_COPYRIGHT).replace("\n", ", "));
|
qInfo() << qPrintable(BuildConfig.LAUNCHER_DISPLAYNAME + ", " + QString(BuildConfig.LAUNCHER_COPYRIGHT).replace("\n", ", "));
|
||||||
qDebug() << "Version : " << BuildConfig.printableVersionString();
|
qInfo() << "Version : " << BuildConfig.printableVersionString();
|
||||||
qDebug() << "Platform : " << BuildConfig.BUILD_PLATFORM;
|
qInfo() << "Platform : " << BuildConfig.BUILD_PLATFORM;
|
||||||
qDebug() << "Git commit : " << BuildConfig.GIT_COMMIT;
|
qInfo() << "Git commit : " << BuildConfig.GIT_COMMIT;
|
||||||
qDebug() << "Git refspec : " << BuildConfig.GIT_REFSPEC;
|
qInfo() << "Git refspec : " << BuildConfig.GIT_REFSPEC;
|
||||||
qDebug() << "Compiled for : " << BuildConfig.systemID();
|
qInfo() << "Compiled for : " << BuildConfig.systemID();
|
||||||
qDebug() << "Compiled by : " << BuildConfig.compilerID();
|
qInfo() << "Compiled by : " << BuildConfig.compilerID();
|
||||||
qDebug() << "Build Artifact : " << BuildConfig.BUILD_ARTIFACT;
|
qInfo() << "Build Artifact : " << BuildConfig.BUILD_ARTIFACT;
|
||||||
qDebug() << "Updates Enabled : " << (updaterEnabled() ? "Yes" : "No");
|
qInfo() << "Updates Enabled : " << (updaterEnabled() ? "Yes" : "No");
|
||||||
if (adjustedBy.size()) {
|
if (adjustedBy.size()) {
|
||||||
qDebug() << "Work dir before adjustment : " << origcwdPath;
|
qInfo() << "Work dir before adjustment : " << origcwdPath;
|
||||||
qDebug() << "Work dir after adjustment : " << QDir::currentPath();
|
qInfo() << "Work dir after adjustment : " << QDir::currentPath();
|
||||||
qDebug() << "Adjusted by : " << adjustedBy;
|
qInfo() << "Adjusted by : " << adjustedBy;
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Work dir : " << QDir::currentPath();
|
qInfo() << "Work dir : " << QDir::currentPath();
|
||||||
}
|
}
|
||||||
qDebug() << "Binary path : " << binPath;
|
qInfo() << "Binary path : " << binPath;
|
||||||
qDebug() << "Application root path : " << m_rootPath;
|
qInfo() << "Application root path : " << m_rootPath;
|
||||||
if (!m_instanceIdToLaunch.isEmpty()) {
|
if (!m_instanceIdToLaunch.isEmpty()) {
|
||||||
qDebug() << "ID of instance to launch : " << m_instanceIdToLaunch;
|
qInfo() << "ID of instance to launch : " << m_instanceIdToLaunch;
|
||||||
}
|
}
|
||||||
if (!m_serverToJoin.isEmpty()) {
|
if (!m_serverToJoin.isEmpty()) {
|
||||||
qDebug() << "Address of server to join :" << m_serverToJoin;
|
qInfo() << "Address of server to join :" << m_serverToJoin;
|
||||||
} else if (!m_worldToJoin.isEmpty()) {
|
} else if (!m_worldToJoin.isEmpty()) {
|
||||||
qDebug() << "Name of the world to join :" << m_worldToJoin;
|
qInfo() << "Name of the world to join :" << m_worldToJoin;
|
||||||
}
|
}
|
||||||
qDebug() << "<> Paths set.";
|
qInfo() << "<> Paths set.";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_liveCheck) {
|
if (m_liveCheck) {
|
||||||
@ -818,7 +891,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
PixmapCache::setInstance(new PixmapCache(this));
|
PixmapCache::setInstance(new PixmapCache(this));
|
||||||
|
|
||||||
qDebug() << "<> Settings loaded.";
|
qInfo() << "<> Settings loaded.";
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef QT_NO_ACCESSIBILITY
|
#ifndef QT_NO_ACCESSIBILITY
|
||||||
@ -834,7 +907,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
QString user = settings()->get("ProxyUser").toString();
|
QString user = settings()->get("ProxyUser").toString();
|
||||||
QString pass = settings()->get("ProxyPass").toString();
|
QString pass = settings()->get("ProxyPass").toString();
|
||||||
updateProxySettings(proxyTypeStr, addr, port, user, pass);
|
updateProxySettings(proxyTypeStr, addr, port, user, pass);
|
||||||
qDebug() << "<> Network done.";
|
qInfo() << "<> Network done.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// load translations
|
// load translations
|
||||||
@ -842,8 +915,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
m_translations.reset(new TranslationsModel("translations"));
|
m_translations.reset(new TranslationsModel("translations"));
|
||||||
auto bcp47Name = m_settings->get("Language").toString();
|
auto bcp47Name = m_settings->get("Language").toString();
|
||||||
m_translations->selectLanguage(bcp47Name);
|
m_translations->selectLanguage(bcp47Name);
|
||||||
qDebug() << "Your language is" << bcp47Name;
|
qInfo() << "Your language is" << bcp47Name;
|
||||||
qDebug() << "<> Translations loaded.";
|
qInfo() << "<> Translations loaded.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instance icons
|
// Instance icons
|
||||||
@ -854,7 +927,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
m_icons.reset(new IconList(instFolders, setting->get().toString()));
|
m_icons.reset(new IconList(instFolders, setting->get().toString()));
|
||||||
connect(setting.get(), &Setting::SettingChanged,
|
connect(setting.get(), &Setting::SettingChanged,
|
||||||
[this](const Setting&, QVariant value) { m_icons->directoryChanged(value.toString()); });
|
[this](const Setting&, QVariant value) { m_icons->directoryChanged(value.toString()); });
|
||||||
qDebug() << "<> Instance icons initialized.";
|
qInfo() << "<> Instance icons initialized.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Themes
|
// Themes
|
||||||
@ -866,25 +939,25 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
// instance path: check for problems with '!' in instance path and warn the user in the log
|
// instance path: check for problems with '!' in instance path and warn the user in the log
|
||||||
// and remember that we have to show him a dialog when the gui starts (if it does so)
|
// and remember that we have to show him a dialog when the gui starts (if it does so)
|
||||||
QString instDir = InstDirSetting->get().toString();
|
QString instDir = InstDirSetting->get().toString();
|
||||||
qDebug() << "Instance path : " << instDir;
|
qInfo() << "Instance path : " << instDir;
|
||||||
if (FS::checkProblemticPathJava(QDir(instDir))) {
|
if (FS::checkProblemticPathJava(QDir(instDir))) {
|
||||||
qWarning() << "Your instance path contains \'!\' and this is known to cause java problems!";
|
qWarning() << "Your instance path contains \'!\' and this is known to cause java problems!";
|
||||||
}
|
}
|
||||||
m_instances.reset(new InstanceList(m_settings, instDir, this));
|
m_instances.reset(new InstanceList(m_settings, instDir, this));
|
||||||
connect(InstDirSetting.get(), &Setting::SettingChanged, m_instances.get(), &InstanceList::on_InstFolderChanged);
|
connect(InstDirSetting.get(), &Setting::SettingChanged, m_instances.get(), &InstanceList::on_InstFolderChanged);
|
||||||
qDebug() << "Loading Instances...";
|
qInfo() << "Loading Instances...";
|
||||||
m_instances->loadList();
|
m_instances->loadList();
|
||||||
qDebug() << "<> Instances loaded.";
|
qInfo() << "<> Instances loaded.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// and accounts
|
// and accounts
|
||||||
{
|
{
|
||||||
m_accounts.reset(new AccountList(this));
|
m_accounts.reset(new AccountList(this));
|
||||||
qDebug() << "Loading accounts...";
|
qInfo() << "Loading accounts...";
|
||||||
m_accounts->setListFilePath("accounts.json", true);
|
m_accounts->setListFilePath("accounts.json", true);
|
||||||
m_accounts->loadList();
|
m_accounts->loadList();
|
||||||
m_accounts->fillQueue();
|
m_accounts->fillQueue();
|
||||||
qDebug() << "<> Accounts loaded.";
|
qInfo() << "<> Accounts loaded.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// init the http meta cache
|
// init the http meta cache
|
||||||
@ -905,7 +978,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
m_metacache->addBase("meta", QDir("meta").absolutePath());
|
m_metacache->addBase("meta", QDir("meta").absolutePath());
|
||||||
m_metacache->addBase("java", QDir("cache/java").absolutePath());
|
m_metacache->addBase("java", QDir("cache/java").absolutePath());
|
||||||
m_metacache->Load();
|
m_metacache->Load();
|
||||||
qDebug() << "<> Cache initialized.";
|
qInfo() << "<> Cache initialized.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// now we have network, download translation updates
|
// now we have network, download translation updates
|
||||||
|
@ -99,7 +99,7 @@ set(CORE_SOURCES
|
|||||||
MTPixmapCache.h
|
MTPixmapCache.h
|
||||||
)
|
)
|
||||||
if (UNIX AND NOT CYGWIN AND NOT APPLE)
|
if (UNIX AND NOT CYGWIN AND NOT APPLE)
|
||||||
set(CORE_SOURCES
|
set(CORE_SOURCES
|
||||||
${CORE_SOURCES}
|
${CORE_SOURCES}
|
||||||
|
|
||||||
# MangoHud
|
# MangoHud
|
||||||
@ -589,8 +589,8 @@ set(ATLAUNCHER_SOURCES
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(LINKEXE_SOURCES
|
set(LINKEXE_SOURCES
|
||||||
WindowsConsole.cpp
|
console/WindowsConsole.h
|
||||||
WindowsConsole.h
|
console/WindowsConsole.cpp
|
||||||
|
|
||||||
filelink/FileLink.h
|
filelink/FileLink.h
|
||||||
filelink/FileLink.cpp
|
filelink/FileLink.cpp
|
||||||
@ -659,6 +659,14 @@ set(PRISMUPDATER_SOURCES
|
|||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(PRISMUPDATER_SOURCES
|
||||||
|
console/WindowsConsole.h
|
||||||
|
console/WindowsConsole.cpp
|
||||||
|
${PRISMUPDATER_SOURCES}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
######## Logging categories ########
|
######## Logging categories ########
|
||||||
|
|
||||||
ecm_qt_declare_logging_category(CORE_SOURCES
|
ecm_qt_declare_logging_category(CORE_SOURCES
|
||||||
@ -786,6 +794,9 @@ SET(LAUNCHER_SOURCES
|
|||||||
SysInfo.h
|
SysInfo.h
|
||||||
SysInfo.cpp
|
SysInfo.cpp
|
||||||
|
|
||||||
|
# console utils
|
||||||
|
console/Console.h
|
||||||
|
|
||||||
# GUI - general utilities
|
# GUI - general utilities
|
||||||
DesktopServices.h
|
DesktopServices.h
|
||||||
DesktopServices.cpp
|
DesktopServices.cpp
|
||||||
@ -926,7 +937,7 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/pages/instance/McResolver.h
|
ui/pages/instance/McResolver.h
|
||||||
ui/pages/instance/ServerPingTask.cpp
|
ui/pages/instance/ServerPingTask.cpp
|
||||||
ui/pages/instance/ServerPingTask.h
|
ui/pages/instance/ServerPingTask.h
|
||||||
|
|
||||||
# GUI - global settings pages
|
# GUI - global settings pages
|
||||||
ui/pages/global/AccountListPage.cpp
|
ui/pages/global/AccountListPage.cpp
|
||||||
ui/pages/global/AccountListPage.h
|
ui/pages/global/AccountListPage.h
|
||||||
@ -1154,7 +1165,7 @@ SET(LAUNCHER_SOURCES
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (NOT Apple)
|
if (NOT Apple)
|
||||||
set(LAUNCHER_SOURCES
|
set(LAUNCHER_SOURCES
|
||||||
${LAUNCHER_SOURCES}
|
${LAUNCHER_SOURCES}
|
||||||
|
|
||||||
ui/dialogs/UpdateAvailableDialog.h
|
ui/dialogs/UpdateAvailableDialog.h
|
||||||
@ -1164,8 +1175,8 @@ endif()
|
|||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(LAUNCHER_SOURCES
|
set(LAUNCHER_SOURCES
|
||||||
WindowsConsole.cpp
|
console/WindowsConsole.h
|
||||||
WindowsConsole.h
|
console/WindowsConsole.cpp
|
||||||
${LAUNCHER_SOURCES}
|
${LAUNCHER_SOURCES}
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
@ -1325,11 +1336,11 @@ if(APPLE)
|
|||||||
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks/")
|
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks/")
|
||||||
|
|
||||||
if(Launcher_ENABLE_UPDATER)
|
if(Launcher_ENABLE_UPDATER)
|
||||||
file(DOWNLOAD ${MACOSX_SPARKLE_DOWNLOAD_URL} ${CMAKE_BINARY_DIR}/Sparkle.tar.xz EXPECTED_HASH SHA256=${MACOSX_SPARKLE_SHA256})
|
file(DOWNLOAD ${MACOSX_SPARKLE_DOWNLOAD_URL} ${CMAKE_BINARY_DIR}/Sparkle.tar.xz EXPECTED_HASH SHA256=${MACOSX_SPARKLE_SHA256})
|
||||||
file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/Sparkle.tar.xz DESTINATION ${CMAKE_BINARY_DIR}/frameworks/Sparkle)
|
file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/Sparkle.tar.xz DESTINATION ${CMAKE_BINARY_DIR}/frameworks/Sparkle)
|
||||||
|
|
||||||
find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
||||||
add_compile_definitions(SPARKLE_ENABLED)
|
add_compile_definitions(SPARKLE_ENABLED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(Launcher_logic
|
target_link_libraries(Launcher_logic
|
||||||
@ -1339,7 +1350,7 @@ if(APPLE)
|
|||||||
"-framework ApplicationServices"
|
"-framework ApplicationServices"
|
||||||
)
|
)
|
||||||
if(Launcher_ENABLE_UPDATER)
|
if(Launcher_ENABLE_UPDATER)
|
||||||
target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK})
|
target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -428,7 +428,7 @@ static QMap<InstanceId, InstanceLocator> getIdMapping(const QList<InstancePtr>&
|
|||||||
|
|
||||||
QList<InstanceId> InstanceList::discoverInstances()
|
QList<InstanceId> InstanceList::discoverInstances()
|
||||||
{
|
{
|
||||||
qDebug() << "Discovering instances in" << m_instDir;
|
qInfo() << "Discovering instances in" << m_instDir;
|
||||||
QList<InstanceId> out;
|
QList<InstanceId> out;
|
||||||
QDirIterator iter(m_instDir, QDir::Dirs | QDir::NoDot | QDir::NoDotDot | QDir::Readable | QDir::Hidden, QDirIterator::FollowSymlinks);
|
QDirIterator iter(m_instDir, QDir::Dirs | QDir::NoDot | QDir::NoDotDot | QDir::Readable | QDir::Hidden, QDirIterator::FollowSymlinks);
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
@ -447,7 +447,7 @@ QList<InstanceId> InstanceList::discoverInstances()
|
|||||||
}
|
}
|
||||||
auto id = dirInfo.fileName();
|
auto id = dirInfo.fileName();
|
||||||
out.append(id);
|
out.append(id);
|
||||||
qDebug() << "Found instance ID" << id;
|
qInfo() << "Found instance ID" << id;
|
||||||
}
|
}
|
||||||
instanceSet = QSet<QString>(out.begin(), out.end());
|
instanceSet = QSet<QString>(out.begin(), out.end());
|
||||||
m_instancesProbed = true;
|
m_instancesProbed = true;
|
||||||
@ -464,7 +464,7 @@ InstanceList::InstListError InstanceList::loadList()
|
|||||||
if (existingIds.contains(id)) {
|
if (existingIds.contains(id)) {
|
||||||
auto instPair = existingIds[id];
|
auto instPair = existingIds[id];
|
||||||
existingIds.remove(id);
|
existingIds.remove(id);
|
||||||
qDebug() << "Should keep and soft-reload" << id;
|
qInfo() << "Should keep and soft-reload" << id;
|
||||||
} else {
|
} else {
|
||||||
InstancePtr instPtr = loadInstance(id);
|
InstancePtr instPtr = loadInstance(id);
|
||||||
if (instPtr) {
|
if (instPtr) {
|
||||||
|
33
launcher/console/Console.h
Normal file
33
launcher/console/Console.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
#if defined Q_OS_WIN32
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <cstdio>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace console {
|
||||||
|
|
||||||
|
inline bool isConsole()
|
||||||
|
{
|
||||||
|
#if defined Q_OS_WIN32
|
||||||
|
DWORD procIDs[2];
|
||||||
|
DWORD maxCount = 2;
|
||||||
|
DWORD result = GetConsoleProcessList((LPDWORD)procIDs, maxCount);
|
||||||
|
return result > 1;
|
||||||
|
#else
|
||||||
|
if (isatty(fileno(stdout))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace console
|
@ -16,13 +16,18 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "WindowsConsole.h"
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#endif
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <windows.h>
|
#include <cstddef>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
void RedirectHandle(DWORD handle, FILE* stream, const char* mode)
|
void RedirectHandle(DWORD handle, FILE* stream, const char* mode)
|
||||||
@ -126,3 +131,29 @@ bool AttachWindowsConsole()
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::error_code EnableAnsiSupport()
|
||||||
|
{
|
||||||
|
// ref: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
|
||||||
|
// Using `CreateFileW("CONOUT$", ...)` to retrieve the console handle works correctly even if STDOUT and/or STDERR are redirected
|
||||||
|
HANDLE console_handle = CreateFileW(L"CONOUT$", FILE_GENERIC_READ | FILE_GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
|
||||||
|
if (console_handle == INVALID_HANDLE_VALUE) {
|
||||||
|
return std::error_code(GetLastError(), std::system_category());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ref: https://docs.microsoft.com/en-us/windows/console/getconsolemode
|
||||||
|
DWORD console_mode;
|
||||||
|
if (0 == GetConsoleMode(console_handle, &console_mode)) {
|
||||||
|
return std::error_code(GetLastError(), std::system_category());
|
||||||
|
}
|
||||||
|
|
||||||
|
// VT processing not already enabled?
|
||||||
|
if ((console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0) {
|
||||||
|
// https://docs.microsoft.com/en-us/windows/console/setconsolemode
|
||||||
|
if (0 == SetConsoleMode(console_handle, console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
|
||||||
|
return std::error_code(GetLastError(), std::system_category());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
@ -21,5 +21,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
void BindCrtHandlesToStdHandles(bool bindStdIn, bool bindStdOut, bool bindStdErr);
|
void BindCrtHandlesToStdHandles(bool bindStdIn, bool bindStdOut, bool bindStdErr);
|
||||||
bool AttachWindowsConsole();
|
bool AttachWindowsConsole();
|
||||||
|
std::error_code EnableAnsiSupport();
|
@ -37,7 +37,10 @@
|
|||||||
#include <sys.h>
|
#include <sys.h>
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
#include "WindowsConsole.h"
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include "console/WindowsConsole.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
@ -46,11 +46,8 @@
|
|||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#endif
|
#endif
|
||||||
#include <fcntl.h>
|
|
||||||
#include <io.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <iostream>
|
#include "console/WindowsConsole.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
@ -87,112 +84,12 @@ void appDebugOutput(QtMsgType type, const QMessageLogContext& context, const QSt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
|
||||||
|
|
||||||
// taken from https://stackoverflow.com/a/25927081
|
|
||||||
// getting a proper output to console with redirection support on windows is apparently hell
|
|
||||||
void BindCrtHandlesToStdHandles(bool bindStdIn, bool bindStdOut, bool bindStdErr)
|
|
||||||
{
|
|
||||||
// Re-initialize the C runtime "FILE" handles with clean handles bound to "nul". We do this because it has been
|
|
||||||
// observed that the file number of our standard handle file objects can be assigned internally to a value of -2
|
|
||||||
// when not bound to a valid target, which represents some kind of unknown internal invalid state. In this state our
|
|
||||||
// call to "_dup2" fails, as it specifically tests to ensure that the target file number isn't equal to this value
|
|
||||||
// before allowing the operation to continue. We can resolve this issue by first "re-opening" the target files to
|
|
||||||
// use the "nul" device, which will place them into a valid state, after which we can redirect them to our target
|
|
||||||
// using the "_dup2" function.
|
|
||||||
if (bindStdIn) {
|
|
||||||
FILE* dummyFile;
|
|
||||||
freopen_s(&dummyFile, "nul", "r", stdin);
|
|
||||||
}
|
|
||||||
if (bindStdOut) {
|
|
||||||
FILE* dummyFile;
|
|
||||||
freopen_s(&dummyFile, "nul", "w", stdout);
|
|
||||||
}
|
|
||||||
if (bindStdErr) {
|
|
||||||
FILE* dummyFile;
|
|
||||||
freopen_s(&dummyFile, "nul", "w", stderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Redirect unbuffered stdin from the current standard input handle
|
|
||||||
if (bindStdIn) {
|
|
||||||
HANDLE stdHandle = GetStdHandle(STD_INPUT_HANDLE);
|
|
||||||
if (stdHandle != INVALID_HANDLE_VALUE) {
|
|
||||||
int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
|
|
||||||
if (fileDescriptor != -1) {
|
|
||||||
FILE* file = _fdopen(fileDescriptor, "r");
|
|
||||||
if (file != NULL) {
|
|
||||||
int dup2Result = _dup2(_fileno(file), _fileno(stdin));
|
|
||||||
if (dup2Result == 0) {
|
|
||||||
setvbuf(stdin, NULL, _IONBF, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Redirect unbuffered stdout to the current standard output handle
|
|
||||||
if (bindStdOut) {
|
|
||||||
HANDLE stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
if (stdHandle != INVALID_HANDLE_VALUE) {
|
|
||||||
int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
|
|
||||||
if (fileDescriptor != -1) {
|
|
||||||
FILE* file = _fdopen(fileDescriptor, "w");
|
|
||||||
if (file != NULL) {
|
|
||||||
int dup2Result = _dup2(_fileno(file), _fileno(stdout));
|
|
||||||
if (dup2Result == 0) {
|
|
||||||
setvbuf(stdout, NULL, _IONBF, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Redirect unbuffered stderr to the current standard error handle
|
|
||||||
if (bindStdErr) {
|
|
||||||
HANDLE stdHandle = GetStdHandle(STD_ERROR_HANDLE);
|
|
||||||
if (stdHandle != INVALID_HANDLE_VALUE) {
|
|
||||||
int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
|
|
||||||
if (fileDescriptor != -1) {
|
|
||||||
FILE* file = _fdopen(fileDescriptor, "w");
|
|
||||||
if (file != NULL) {
|
|
||||||
int dup2Result = _dup2(_fileno(file), _fileno(stderr));
|
|
||||||
if (dup2Result == 0) {
|
|
||||||
setvbuf(stderr, NULL, _IONBF, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the error state for each of the C++ standard stream objects. We need to do this, as attempts to access the
|
|
||||||
// standard streams before they refer to a valid target will cause the iostream objects to enter an error state. In
|
|
||||||
// versions of Visual Studio after 2005, this seems to always occur during startup regardless of whether anything
|
|
||||||
// has been read from or written to the targets or not.
|
|
||||||
if (bindStdIn) {
|
|
||||||
std::wcin.clear();
|
|
||||||
std::cin.clear();
|
|
||||||
}
|
|
||||||
if (bindStdOut) {
|
|
||||||
std::wcout.clear();
|
|
||||||
std::cout.clear();
|
|
||||||
}
|
|
||||||
if (bindStdErr) {
|
|
||||||
std::wcerr.clear();
|
|
||||||
std::cerr.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PrismUpdaterApp::PrismUpdaterApp(int& argc, char** argv) : QApplication(argc, argv)
|
PrismUpdaterApp::PrismUpdaterApp(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
{
|
{
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
// attach the parent console if stdout not already captured
|
// attach the parent console if stdout not already captured
|
||||||
auto stdout_type = GetFileType(GetStdHandle(STD_OUTPUT_HANDLE));
|
if (AttachWindowsConsole()) {
|
||||||
if (stdout_type == FILE_TYPE_CHAR || stdout_type == FILE_TYPE_UNKNOWN) {
|
consoleAttached = true;
|
||||||
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
|
||||||
BindCrtHandlesToStdHandles(true, true, true);
|
|
||||||
consoleAttached = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
setOrganizationName(BuildConfig.LAUNCHER_NAME);
|
setOrganizationName(BuildConfig.LAUNCHER_NAME);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user