123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- #include <locale.h>
- #include <QGuiApplication>
- #include <QApplication>
- #include <QFileInfo>
- #include <QIcon>
- #include <QtQml>
- #include <QtWebEngine/qtwebengineglobal.h>
- #include <QErrorMessage>
- #include <QCommandLineOption>
- #include "shared/Names.h"
- #include "system/SystemComponent.h"
- #include "QsLog.h"
- #include "Paths.h"
- #include "player/CodecsComponent.h"
- #include "player/PlayerComponent.h"
- #include "player/OpenGLDetect.h"
- #include "Version.h"
- #include "settings/SettingsComponent.h"
- #include "settings/SettingsSection.h"
- #include "ui/KonvergoWindow.h"
- #include "ui/KonvergoWindow.h"
- #include "Globals.h"
- #include "ui/ErrorMessage.h"
- #include "UniqueApplication.h"
- #include "utils/Log.h"
- #ifdef Q_OS_MAC
- #include "PFMoveApplication.h"
- #endif
- #if defined(Q_OS_MAC) || defined(Q_OS_LINUX)
- #include "SignalManager.h"
- #endif
- /////////////////////////////////////////////////////////////////////////////////////////
- static void preinitQt()
- {
- QCoreApplication::setApplicationName(Names::MainName());
- QCoreApplication::setApplicationVersion(Version::GetVersionString());
- QCoreApplication::setOrganizationDomain("jellyfin.org");
- #ifdef Q_OS_WIN32
- QVariant useOpengl = SettingsComponent::readPreinitValue(SETTINGS_SECTION_MAIN, "useOpenGL");
- // Warning: this must be the same as the default value as declared in
- // the settings_description.json file, or confusion will result.
- if (useOpengl.type() != QMetaType::Bool)
- useOpengl = false;
- if (useOpengl.toBool())
- QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
- else
- QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
- #endif
- }
- /////////////////////////////////////////////////////////////////////////////////////////
- char** appendCommandLineArguments(int argc, char **argv, const QStringList& args)
- {
- size_t newSize = (argc + args.length() + 1) * sizeof(char*);
- char** newArgv = (char**)calloc(1, newSize);
- memcpy(newArgv, argv, (size_t)(argc * sizeof(char*)));
- int pos = argc;
- for(const QString& str : args)
- newArgv[pos++] = qstrdup(str.toUtf8().data());
- return newArgv;
- }
- /////////////////////////////////////////////////////////////////////////////////////////
- void ShowLicenseInfo()
- {
- QFile licenses(":/misc/licenses.txt");
- licenses.open(QIODevice::ReadOnly | QIODevice::Text);
- QByteArray contents = licenses.readAll();
- printf("%.*s\n", contents.size(), contents.data());
- }
- /////////////////////////////////////////////////////////////////////////////////////////
- QStringList g_qtFlags = {
- "--disable-web-security"
- };
- /////////////////////////////////////////////////////////////////////////////////////////
- int main(int argc, char *argv[])
- {
- try
- {
- QCommandLineParser parser;
- parser.setApplicationDescription("Jellyfin Media Player");
- parser.addHelpOption();
- parser.addVersionOption();
- parser.addOptions({{{"l", "licenses"}, "Show license information"},
- {{"a", "from-auto-update"}, "When invoked from auto-update"},
- {"desktop", "Start in desktop mode"},
- {"tv", "Start in TV mode"},
- {"auto-layout", "Use auto-layout mode"},
- {"windowed", "Start in windowed mode"},
- {"fullscreen", "Start in fullscreen"},
- {"no-updates", "Disable auto-updating"},
- {"terminal", "Log to terminal"},
- {"disable-gpu", "Disable QtWebEngine gpu accel"}});
- auto scaleOption = QCommandLineOption("scale-factor", "Set to a integer or default auto which controls" \
- "the scale (DPI) of the desktop interface.");
- scaleOption.setValueName("scale");
- scaleOption.setDefaultValue("auto");
-
- auto devOption = QCommandLineOption("remote-debugging-port", "Port number for devtools.");
- devOption.setValueName("port");
- parser.addOption(scaleOption);
- parser.addOption(devOption);
- char **newArgv = appendCommandLineArguments(argc, argv, g_qtFlags);
- int newArgc = argc + g_qtFlags.size();
- // Qt calls setlocale(LC_ALL, "") in a bunch of places, which breaks
- // float/string processing in mpv and ffmpeg.
- #ifdef Q_OS_UNIX
- qputenv("LC_ALL", "C");
- qputenv("LC_NUMERIC", "C");
- #endif
- preinitQt();
- detectOpenGLEarly();
- QStringList arguments;
- for (int i = 0; i < argc; i++)
- arguments << QString::fromLatin1(argv[i]);
- {
- // This is kinda dumb. But in order for the QCommandLineParser
- // to work properly we need to init if before we call process
- // but we don't want to do that for the main application since
- // we need to set the scale factor before we do that. So it becomes
- // a small chicken-or-egg problem, which we "solve" by making
- // this temporary console app.
- //
- QCoreApplication core(newArgc, newArgv);
- // Now parse the command line.
- parser.process(arguments);
- }
- if (parser.isSet("licenses"))
- {
- ShowLicenseInfo();
- return EXIT_SUCCESS;
- }
- auto scale = parser.value("scale-factor");
- if (scale.isEmpty() || scale == "auto")
- QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
- else if (scale != "none")
- qputenv("QT_SCALE_FACTOR", scale.toUtf8());
- QApplication app(newArgc, newArgv);
- #if defined(Q_OS_WIN) || defined(Q_OS_LINUX)
- // Setting window icon on OSX will break user ability to change it
- app.setWindowIcon(QIcon(":/images/icon.png"));
- #endif
- #if defined(Q_OS_MAC) && defined(NDEBUG)
- PFMoveToApplicationsFolderIfNecessary();
- #endif
- UniqueApplication* uniqueApp = new UniqueApplication();
- if (!uniqueApp->ensureUnique())
- return EXIT_SUCCESS;
- #ifdef Q_OS_UNIX
- // install signals handlers for proper app closing.
- SignalManager signalManager(&app);
- Q_UNUSED(signalManager);
- #endif
- Log::Init();
- if (parser.isSet("terminal"))
- Log::EnableTerminalOutput();
- detectOpenGLLate();
- Codecs::preinitCodecs();
- // Initialize all the components. This needs to be done
- // early since most everything else relies on it
- //
- ComponentManager::Get().initialize();
- SettingsComponent::Get().setCommandLineValues(parser.optionNames());
- // enable remote inspection if we have the correct setting for it.
- if (SettingsComponent::Get().value(SETTINGS_SECTION_MAIN, "remoteInspector").toBool())
- qputenv("QTWEBENGINE_REMOTE_DEBUGGING", "0.0.0.0:9992");
- QtWebEngine::initialize();
- // load QtWebChannel so that we can register our components with it.
- QQmlApplicationEngine *engine = Globals::Engine();
- KonvergoWindow::RegisterClass();
- Globals::SetContextProperty("components", &ComponentManager::Get().getQmlPropertyMap());
- // the only way to detect if QML parsing fails is to hook to this signal and then see
- // if we get a valid object passed to it. Any error messages will be reported on stderr
- // but since no normal user should ever see this it should be fine
- //
- QObject::connect(engine, &QQmlApplicationEngine::objectCreated, [=](QObject* object, const QUrl& url)
- {
- Q_UNUSED(url);
- if (object == nullptr)
- throw FatalException(QObject::tr("Failed to parse application engine script."));
- KonvergoWindow* window = Globals::MainWindow();
- QObject* webChannel = qvariant_cast<QObject*>(window->property("webChannel"));
- Q_ASSERT(webChannel);
- ComponentManager::Get().setWebChannel(qobject_cast<QWebChannel*>(webChannel));
- QObject::connect(uniqueApp, &UniqueApplication::otherApplicationStarted, window, &KonvergoWindow::otherAppFocus);
- });
- engine->load(QUrl(QStringLiteral("qrc:/ui/webview.qml")));
- Log::UpdateLogLevel();
- // run our application
- int ret = app.exec();
- delete uniqueApp;
- Globals::EngineDestroy();
- Codecs::Uninit();
- Log::Uninit();
- return ret;
- }
- catch (FatalException& e)
- {
- QLOG_FATAL() << "Unhandled FatalException:" << qPrintable(e.message());
- QApplication errApp(argc, argv);
- auto msg = new ErrorMessage(e.message(), true);
- msg->show();
- errApp.exec();
- Codecs::Uninit();
- Log::Uninit();
- return 1;
- }
- }
|