main.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. #include <locale.h>
  2. #include <QGuiApplication>
  3. #include <QApplication>
  4. #include <QFileInfo>
  5. #include <QIcon>
  6. #include <QtQml>
  7. #include <QtWebEngine/qtwebengineglobal.h>
  8. #include <QErrorMessage>
  9. #include "shared/Names.h"
  10. #include "system/SystemComponent.h"
  11. #include "system/UpdateManager.h"
  12. #include "QsLog.h"
  13. #include "Paths.h"
  14. #include "player/PlayerComponent.h"
  15. #include "breakpad/CrashDumps.h"
  16. #include "Version.h"
  17. #include "settings/SettingsComponent.h"
  18. #include "settings/SettingsSection.h"
  19. #include "ui/KonvergoWindow.h"
  20. #include "ui/KonvergoEngine.h"
  21. #include "UniqueApplication.h"
  22. #include "utils/HelperLauncher.h"
  23. #include "utils/Log.h"
  24. #if defined(Q_OS_MAC) || defined(Q_OS_LINUX)
  25. #include "SignalManager.h"
  26. #endif
  27. /////////////////////////////////////////////////////////////////////////////////////////
  28. static void preinitQt()
  29. {
  30. QCoreApplication::setApplicationName(Names::MainName());
  31. QCoreApplication::setApplicationVersion(Version::GetVersionString());
  32. QCoreApplication::setOrganizationDomain("plex.tv");
  33. #ifdef Q_OS_WIN32
  34. QVariant useOpengl = SettingsComponent::readPreinitValue(SETTINGS_SECTION_MAIN, "useOpenGL");
  35. // Warning: this must be the same as the default value as declared in
  36. // the settings_description.json file, or confusion will result.
  37. if (useOpengl.type() != QMetaType::Bool)
  38. useOpengl = false;
  39. if (useOpengl.toBool())
  40. QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
  41. else
  42. QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
  43. #endif
  44. }
  45. /////////////////////////////////////////////////////////////////////////////////////////
  46. char** appendCommandLineArguments(int argc, char **argv, const QStringList& args)
  47. {
  48. size_t newSize = (argc + args.length() + 1) * sizeof(char*);
  49. char** newArgv = (char**)calloc(1, newSize);
  50. memcpy(newArgv, argv, (size_t)(argc * sizeof(char*)));
  51. int pos = argc;
  52. foreach(const QString& str, args)
  53. newArgv[pos++] = qstrdup(str.toUtf8().data());
  54. return newArgv;
  55. }
  56. /////////////////////////////////////////////////////////////////////////////////////////
  57. void ShowLicenseInfo()
  58. {
  59. QFile licenses(":/misc/licenses.txt");
  60. licenses.open(QIODevice::ReadOnly | QIODevice::Text);
  61. QByteArray contents = licenses.readAll();
  62. printf("%.*s\n", contents.size(), contents.data());
  63. }
  64. /////////////////////////////////////////////////////////////////////////////////////////
  65. int main(int argc, char *argv[])
  66. {
  67. try
  68. {
  69. QCommandLineParser parser;
  70. parser.setApplicationDescription("Plex Media Player");
  71. parser.addHelpOption();
  72. parser.addVersionOption();
  73. parser.addOptions({{{"l", "licenses"}, "Show license information"}});
  74. char **newArgv = appendCommandLineArguments(argc, argv, {"--enable-viewport", "--enable-viewport-meta"});
  75. argc += 2;
  76. #ifdef KONVERGO_OPENELEC
  77. newArgv = appendCommandLineArguments(argc, newArgv, {"--disable-gpu"});
  78. argc ++;
  79. #endif
  80. // Suppress SSL related warnings on OSX
  81. // See https://bugreports.qt.io/browse/QTBUG-43173 for more info
  82. //
  83. #ifdef Q_OS_MAC
  84. qputenv("QT_LOGGING_RULES", "qt.network.ssl.warning=false");
  85. // Request OpenGL 4.1 if possible on OSX, otherwise it defaults to 2.0
  86. // This needs to be done before we create the QGuiApplication
  87. //
  88. QSurfaceFormat format = QSurfaceFormat::defaultFormat();
  89. format.setMajorVersion(3);
  90. format.setMinorVersion(2);
  91. format.setProfile(QSurfaceFormat::CoreProfile);
  92. QSurfaceFormat::setDefaultFormat(format);
  93. #endif
  94. preinitQt();
  95. QGuiApplication app(argc, newArgv);
  96. app.setWindowIcon(QIcon(":/images/icon.png"));
  97. // Get the arguments from the app, this is the parsed version of newArgc and newArgv
  98. QStringList args = app.arguments();
  99. // Remove the viewport arguments so that the parser doesn't barf
  100. args.removeAll("--enable-viewport");
  101. args.removeAll("--enable-viewport-meta");
  102. args.removeAll("--disable-gpu");
  103. // Now parse the command line.
  104. parser.process(args);
  105. if (parser.isSet("licenses"))
  106. {
  107. ShowLicenseInfo();
  108. return EXIT_SUCCESS;
  109. }
  110. // init breakpad.
  111. setupCrashDumper();
  112. UniqueApplication* uniqueApp = new UniqueApplication();
  113. if (!uniqueApp->ensureUnique())
  114. return EXIT_SUCCESS;
  115. #ifdef Q_OS_UNIX
  116. // install signals handlers for proper app closing.
  117. SignalManager signalManager(&app);
  118. Q_UNUSED(signalManager);
  119. #endif
  120. Log::Init();
  121. // Quit app and apply update if we find one.
  122. if (UpdateManager::CheckForUpdates())
  123. {
  124. app.quit();
  125. return 0;
  126. }
  127. #ifdef Q_OS_WIN32
  128. initD3DDevice();
  129. #endif
  130. #ifdef Q_OS_UNIX
  131. setlocale(LC_NUMERIC, "C");
  132. #endif
  133. // Initialize all the components. This needs to be done
  134. // early since most everything else relies on it
  135. //
  136. ComponentManager::Get().initialize();
  137. // enable remote inspection if we have the correct setting for it.
  138. if (SettingsComponent::Get().value(SETTINGS_SECTION_MAIN, "remoteInspector").toBool())
  139. qputenv("QTWEBENGINE_REMOTE_DEBUGGING", "0.0.0.0:9992");
  140. QtWebEngine::initialize();
  141. // Qt and QWebEngineProfile set the locale, which breaks parsing and
  142. // formatting float numbers in a few countries.
  143. #ifdef Q_OS_UNIX
  144. setlocale(LC_NUMERIC, "C");
  145. #endif
  146. // start our helper
  147. HelperLauncher::Get().connectToHelper();
  148. // load QtWebChannel so that we can register our components with it.
  149. QQmlApplicationEngine *engine = KonvergoEngine::Get();
  150. KonvergoWindow::RegisterClass();
  151. engine->rootContext()->setContextProperty("components", &ComponentManager::Get().getQmlPropertyMap());
  152. // the only way to detect if QML parsing fails is to hook to this signal and then see
  153. // if we get a valid object passed to it. Any error messages will be reported on stderr
  154. // but since no normal user should ever see this it should be fine
  155. //
  156. QObject::connect(engine, &QQmlApplicationEngine::objectCreated, [=](QObject* object, const QUrl& url)
  157. {
  158. Q_UNUSED(url);
  159. if (object == 0)
  160. throw FatalException(QObject::tr("Failed to parse application engine script."));
  161. QObject* rootObject = engine->rootObjects().first();
  162. QObject* webChannel = qvariant_cast<QObject*>(rootObject->property("webChannel"));
  163. Q_ASSERT(webChannel);
  164. ComponentManager::Get().setWebChannel(qobject_cast<QWebChannel*>(webChannel));
  165. KonvergoWindow* window = qobject_cast<KonvergoWindow*>(rootObject);
  166. Q_ASSERT(window);
  167. QObject::connect(uniqueApp, &UniqueApplication::otherApplicationStarted, window, &KonvergoWindow::otherAppFocus);
  168. });
  169. engine->load(QUrl(QStringLiteral("qrc:/ui/webview.qml")));
  170. Log::UpdateLogLevel();
  171. // run our application
  172. int ret = app.exec();
  173. delete KonvergoEngine::Get();
  174. delete uniqueApp;
  175. return ret;
  176. }
  177. catch (FatalException& e)
  178. {
  179. QLOG_FATAL() << "Unhandled FatalException:" << qPrintable(e.message());
  180. QApplication errApp(argc, argv);
  181. QErrorMessage* msg = new QErrorMessage;
  182. msg->showMessage("Plex Media Player encountered a fatal error and will now quit: " + e.message());
  183. QObject::connect(msg, &QErrorMessage::finished, []() { qApp->exit(1); });
  184. errApp.exec();
  185. return 1;
  186. }
  187. }