moonlight-qt/app/main.cpp

231 lines
7.1 KiB
C++
Raw Normal View History

2018-07-04 21:16:25 +00:00
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QIcon>
2018-07-09 06:24:26 +00:00
#include <QQuickStyle>
#include <QMutex>
#include <QtDebug>
2018-04-28 22:39:50 +00:00
2018-06-24 05:16:59 +00:00
// Don't let SDL hook our main function, since Qt is already
2018-07-07 23:37:11 +00:00
// doing the same thing. This needs to be before any headers
// that might include SDL.h themselves.
2018-06-24 05:16:59 +00:00
#define SDL_MAIN_HANDLED
#include <SDL.h>
#include "path.h"
2018-07-07 23:37:11 +00:00
#include "gui/computermodel.h"
#include "gui/appmodel.h"
#include "backend/autoupdatechecker.h"
2018-07-07 23:37:11 +00:00
#include "streaming/session.hpp"
#include "settings/streamingpreferences.h"
2018-07-07 23:37:11 +00:00
#if !defined(QT_DEBUG) && defined(Q_OS_WIN32)
// Log to file for release Windows builds
#define USE_CUSTOM_LOGGER
#define LOG_TO_FILE
#elif defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
// Use stdout logger on all Linux/BSD builds
#define USE_CUSTOM_LOGGER
#elif !defined(QT_DEBUG) && defined(Q_OS_DARWIN)
// Log to file for release Mac builds
#define USE_CUSTOM_LOGGER
#define LOG_TO_FILE
#else
// For debug Windows and Mac builds, use default logger
#endif
#ifdef USE_CUSTOM_LOGGER
static QTime s_LoggerTime;
static QTextStream s_LoggerStream(stdout);
static QMutex s_LoggerLock;
#ifdef LOG_TO_FILE
2018-07-26 07:21:26 +00:00
#define MAX_LOG_LINES 10000
static int s_LogLinesWritten = 0;
static bool s_LogLimitReached = false;
static QFile* s_LoggerFile;
#endif
2018-07-26 07:21:26 +00:00
void logToLoggerStream(QString& message)
{
QMutexLocker lock(&s_LoggerLock);
#ifdef LOG_TO_FILE
if (s_LogLimitReached) {
return;
}
else if (s_LogLinesWritten == MAX_LOG_LINES) {
s_LoggerStream << "Log size limit reached!" << endl;
s_LogLimitReached = true;
return;
}
else {
s_LogLinesWritten++;
}
#endif
s_LoggerStream << message << endl;
}
void sdlLogToDiskHandler(void*, int category, SDL_LogPriority priority, const char* message)
{
QString priorityTxt;
switch (priority) {
case SDL_LOG_PRIORITY_VERBOSE:
priorityTxt = "Verbose";
break;
case SDL_LOG_PRIORITY_DEBUG:
priorityTxt = "Debug";
break;
case SDL_LOG_PRIORITY_INFO:
priorityTxt = "Info";
break;
case SDL_LOG_PRIORITY_WARN:
priorityTxt = "Warn";
break;
case SDL_LOG_PRIORITY_ERROR:
priorityTxt = "Error";
break;
case SDL_LOG_PRIORITY_CRITICAL:
priorityTxt = "Critical";
break;
2018-07-26 07:21:26 +00:00
default:
priorityTxt = "Unknown";
break;
}
QTime logTime = QTime::fromMSecsSinceStartOfDay(s_LoggerTime.elapsed());
QString txt = QString("%1 - SDL %2 (%3): %4").arg(logTime.toString()).arg(priorityTxt).arg(category).arg(message);
2018-07-26 07:21:26 +00:00
logToLoggerStream(txt);
}
void qtLogToDiskHandler(QtMsgType type, const QMessageLogContext&, const QString& msg)
{
QString typeTxt;
switch (type) {
case QtDebugMsg:
typeTxt = "Debug";
break;
case QtInfoMsg:
typeTxt = "Info";
break;
case QtWarningMsg:
typeTxt = "Warning";
break;
case QtCriticalMsg:
typeTxt = "Critical";
break;
case QtFatalMsg:
typeTxt = "Fatal";
break;
}
QTime logTime = QTime::fromMSecsSinceStartOfDay(s_LoggerTime.elapsed());
QString txt = QString("%1 - Qt %2: %3").arg(logTime.toString()).arg(typeTxt).arg(msg);
2018-07-26 07:21:26 +00:00
logToLoggerStream(txt);
}
#endif
2018-04-28 22:39:50 +00:00
int main(int argc, char *argv[])
{
// Set these here to allow us to use the default QSettings constructor.
// These also ensure that our cache directory is named correctly. As such,
// it is critical that these be called before Path::initialize().
QCoreApplication::setOrganizationName("Moonlight Game Streaming Project");
QCoreApplication::setOrganizationDomain("moonlight-stream.com");
QCoreApplication::setApplicationName("Moonlight");
if (QFile(QDir::currentPath() + "/portable.dat").exists()) {
qInfo() << "Running in portable mode from:" << QDir::currentPath();
QSettings::setDefaultFormat(QSettings::IniFormat);
QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, QDir::currentPath());
QSettings::setPath(QSettings::IniFormat, QSettings::SystemScope, QDir::currentPath());
// Initialize paths for portable mode
Path::initialize(true);
}
else {
// Initialize paths for standard installation
Path::initialize(false);
}
#ifdef USE_CUSTOM_LOGGER
#ifdef LOG_TO_FILE
QDir tempDir(Path::getLogDir());
s_LoggerFile = new QFile(tempDir.filePath(QString("Moonlight-%1.log").arg(QDateTime::currentSecsSinceEpoch())));
if (s_LoggerFile->open(QIODevice::WriteOnly)) {
qInfo() << "Redirecting log output to " << s_LoggerFile->fileName();
s_LoggerStream.setDevice(s_LoggerFile);
}
#endif
s_LoggerTime.start();
qInstallMessageHandler(qtLogToDiskHandler);
SDL_LogSetOutputFunction(sdlLogToDiskHandler, nullptr);
#endif
2018-07-04 21:16:25 +00:00
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
2018-05-06 04:59:30 +00:00
// This avoids using the default keychain for SSL, which may cause
// password prompts on macOS.
qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1"));
2018-08-25 18:59:32 +00:00
#ifdef Q_OS_WIN32
// On Windows, use ANGLE so we don't have to load both DX and OGL
// user-mode drivers into our app.
qputenv("QT_OPENGL", "angle");
#endif
// Register custom metatypes for use in signals
qRegisterMetaType<NvApp>("NvApp");
2018-07-04 21:16:25 +00:00
QGuiApplication app(argc, argv);
app.setWindowIcon(QIcon(":/res/moonlight.svg"));
2018-07-04 23:40:21 +00:00
// Register our C++ types for QML
qmlRegisterType<ComputerModel>("ComputerModel", 1, 0, "ComputerModel");
qmlRegisterType<AppModel>("AppModel", 1, 0, "AppModel");
qmlRegisterType<StreamingPreferences>("StreamingPreferences", 1, 0, "StreamingPreferences");
qmlRegisterUncreatableType<Session>("Session", 1, 0, "Session", "Session cannot be created from QML");
qmlRegisterSingletonType<ComputerManager>("ComputerManager", 1, 0,
"ComputerManager",
[](QQmlEngine*, QJSEngine*) -> QObject* {
return new ComputerManager();
});
qmlRegisterSingletonType<AutoUpdateChecker>("AutoUpdateChecker", 1, 0,
"AutoUpdateChecker",
[](QQmlEngine*, QJSEngine*) -> QObject* {
return new AutoUpdateChecker();
});
2018-07-04 23:40:21 +00:00
2018-07-09 06:24:26 +00:00
QQuickStyle::setStyle("Material");
2018-07-04 21:16:25 +00:00
// Load the main.qml file
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/gui/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
2018-04-28 22:39:50 +00:00
2018-06-24 05:16:59 +00:00
SDL_SetMainReady();
if (SDL_Init(0) != 0) {
2018-06-24 05:16:59 +00:00
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_Init() failed: %s",
SDL_GetError());
}
// Avoid the default behavior of changing the timer resolution to 1 ms.
// We don't want this all the time that Moonlight is open. We will set
// it manually when we start streaming.
SDL_SetHint(SDL_HINT_TIMER_RESOLUTION, "0");
2018-07-04 21:16:25 +00:00
int err = app.exec();
2018-06-24 05:16:59 +00:00
SDL_Quit();
2018-06-24 05:16:59 +00:00
return err;
2018-04-28 22:39:50 +00:00
}