main.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #include <QDebug>
  2. #include <QTextCodec>
  3. #include <QSslSocket>
  4. #include <QLocale>
  5. #include <QTranslator>
  6. #include <QScopedPointer>
  7. #include <QOpenGLContext>
  8. #include <QDateTime>
  9. #include <QSysInfo>
  10. #include <QProcess>
  11. #include <QWebEngineSettings>
  12. #include <QWindow>
  13. #include <QAccessible>
  14. #include <core/configmgr.h>
  15. #include <core/mainconfig.h>
  16. #include <core/coreconfig.h>
  17. #include <core/sessionconfig.h>
  18. #include <core/singleinstanceguard.h>
  19. #include <core/vnotex.h>
  20. #include <core/logger.h>
  21. #include <widgets/mainwindow.h>
  22. #include <core/exception.h>
  23. #include <utils/widgetutils.h>
  24. #include <widgets/messageboxhelper.h>
  25. #include "commandlineoptions.h"
  26. #include "application.h"
  27. #include "fakeaccessible.h"
  28. using namespace vnotex;
  29. void loadTranslators(QApplication &p_app);
  30. void initWebEngineSettings();
  31. void showMessageOnCommandLineIfAvailable(const QString &p_msg);
  32. int main(int argc, char *argv[])
  33. {
  34. QTextCodec *codec = QTextCodec::codecForName("UTF8");
  35. if (codec) {
  36. QTextCodec::setCodecForLocale(codec);
  37. }
  38. QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
  39. // This only takes effect on Win, X11 and Android.
  40. QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
  41. // Set OpenGL option on Windows.
  42. // Set environment QT_OPENGL to "angle/desktop/software".
  43. #if defined(Q_OS_WIN)
  44. {
  45. auto option = SessionConfig::getOpenGLAtBootstrap();
  46. qDebug() << "OpenGL option" << SessionConfig::openGLToString(option);
  47. switch (option) {
  48. case SessionConfig::OpenGL::Desktop:
  49. QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
  50. break;
  51. case SessionConfig::OpenGL::Angle:
  52. QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
  53. break;
  54. case SessionConfig::OpenGL::Software:
  55. QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
  56. break;
  57. default:
  58. break;
  59. }
  60. }
  61. #endif
  62. Application app(argc, argv);
  63. initWebEngineSettings();
  64. QAccessible::installFactory(&FakeAccessible::accessibleFactory);
  65. {
  66. const QString iconPath = ":/vnotex/data/core/icons/vnote.ico";
  67. // Make sense only on Windows.
  68. app.setWindowIcon(QIcon(iconPath));
  69. app.setApplicationName(ConfigMgr::c_appName);
  70. app.setOrganizationName(ConfigMgr::c_orgName);
  71. app.setApplicationVersion(ConfigMgr::getApplicationVersion());
  72. }
  73. CommandLineOptions cmdOptions;
  74. switch (cmdOptions.parse(app.arguments())) {
  75. case CommandLineOptions::Ok:
  76. break;
  77. case CommandLineOptions::Error:
  78. fprintf(stderr, "%s\n", qPrintable(cmdOptions.m_errorMsg));
  79. // Arguments to WebEngineView will be unknown ones. So just let it go.
  80. break;
  81. case CommandLineOptions::VersionRequested:
  82. {
  83. auto versionStr = QString("%1 %2").arg(app.applicationName()).arg(app.applicationVersion());
  84. showMessageOnCommandLineIfAvailable(versionStr);
  85. return 0;
  86. }
  87. case CommandLineOptions::HelpRequested:
  88. Q_FALLTHROUGH();
  89. default:
  90. showMessageOnCommandLineIfAvailable(cmdOptions.m_helpText);
  91. return 0;
  92. }
  93. // Guarding.
  94. SingleInstanceGuard guard;
  95. bool canRun = guard.tryRun();
  96. if (!canRun) {
  97. guard.requestOpenFiles(cmdOptions.m_pathsToOpen);
  98. guard.requestShow();
  99. return 0;
  100. }
  101. try {
  102. ConfigMgr::getInst();
  103. } catch (Exception &e) {
  104. MessageBoxHelper::notify(MessageBoxHelper::Critical,
  105. MainWindow::tr("%1 failed to start.").arg(ConfigMgr::c_appName),
  106. MainWindow::tr("Failed to initialize configuration manager. "
  107. "Please check if all the files are intact or reinstall the application."),
  108. e.what());
  109. return -1;
  110. }
  111. // Init logger after app info is set.
  112. Logger::init(cmdOptions.m_verbose);
  113. qInfo() << QString("%1 (v%2) started at %3 (%4)").arg(ConfigMgr::c_appName,
  114. app.applicationVersion(),
  115. QDateTime::currentDateTime().toString(),
  116. QSysInfo::productType());
  117. qInfo() << "OpenSSL build version:" << QSslSocket::sslLibraryBuildVersionString()
  118. << "link version:" << QSslSocket::sslLibraryVersionString();
  119. if (QSslSocket::sslLibraryBuildVersionNumber() != QSslSocket::sslLibraryVersionNumber()) {
  120. qWarning() << "versions of the built and linked OpenSSL mismatch, network may not work";
  121. }
  122. // Should set the correct locale before VNoteX::getInst().
  123. loadTranslators(app);
  124. MainWindow window;
  125. window.show();
  126. QObject::connect(&guard, &SingleInstanceGuard::showRequested,
  127. &window, &MainWindow::showMainWindow);
  128. QObject::connect(&guard, &SingleInstanceGuard::openFilesRequested,
  129. &window, &MainWindow::openFiles);
  130. QObject::connect(&app, &Application::openFileRequested,
  131. &window, [&window](const QString &p_filePath) {
  132. window.openFiles(QStringList() << p_filePath);
  133. });
  134. // Let MainWindow show first to decide the screen on which app is running.
  135. WidgetUtils::calculateScaleFactor(window.windowHandle()->screen());
  136. if (app.styleSheet().isEmpty()) {
  137. auto style = VNoteX::getInst().getThemeMgr().fetchQtStyleSheet();
  138. if (!style.isEmpty()) {
  139. app.setStyleSheet(style);
  140. WidgetUtils::updateStyle(&window);
  141. }
  142. }
  143. VNoteX::getInst().getThemeMgr().setBaseBackground(window.palette().color(QPalette::Base));
  144. window.kickOffOnStart(cmdOptions.m_pathsToOpen);
  145. int ret = app.exec();
  146. if (ret == RESTART_EXIT_CODE) {
  147. // Asked to restart VNote.
  148. guard.exit();
  149. QProcess::startDetached(QCoreApplication::applicationFilePath(), QStringList());
  150. // Must use exit() in Linux to quit the parent process in Qt 5.12.
  151. // Thanks to @ygcaicn.
  152. exit(0);
  153. return 0;
  154. }
  155. return ret;
  156. }
  157. void loadTranslators(QApplication &p_app)
  158. {
  159. auto localeName = ConfigMgr::getInst().getCoreConfig().getLocale();
  160. if (!localeName.isEmpty()) {
  161. QLocale::setDefault(QLocale(localeName));
  162. }
  163. QLocale locale;
  164. qInfo() << "locale:" << locale.name();
  165. const QString resourceTranslationFolder(QStringLiteral(":/vnotex/data/core/translations"));
  166. const QString envTranslationFolder(QStringLiteral("translations"));
  167. // For QTextEdit/QTextBrowser and other basic widgets.
  168. QScopedPointer<QTranslator> qtbaseTranslator(new QTranslator(&p_app));
  169. if (qtbaseTranslator->load(locale, "qtbase", "_", resourceTranslationFolder)) {
  170. p_app.installTranslator(qtbaseTranslator.take());
  171. }
  172. // qt_zh_CN.ts does not cover the real QDialogButtonBox which uses QPlatformTheme.
  173. QScopedPointer<QTranslator> dialogButtonBoxTranslator(new QTranslator(&p_app));
  174. if (dialogButtonBoxTranslator->load(locale, "qdialogbuttonbox", "_", resourceTranslationFolder)) {
  175. p_app.installTranslator(dialogButtonBoxTranslator.take());
  176. }
  177. QScopedPointer<QTranslator> webengineTranslator(new QTranslator(&p_app));
  178. if (webengineTranslator->load(locale, "qwebengine", "_", resourceTranslationFolder)) {
  179. p_app.installTranslator(webengineTranslator.take());
  180. }
  181. // Load translation for Qt from resource.
  182. QScopedPointer<QTranslator> qtTranslator(new QTranslator(&p_app));
  183. if (qtTranslator->load(locale, "qt", "_", resourceTranslationFolder)) {
  184. p_app.installTranslator(qtTranslator.take());
  185. }
  186. // Load translation for Qt from env.
  187. QScopedPointer<QTranslator> qtEnvTranslator(new QTranslator(&p_app));
  188. if (qtEnvTranslator->load(locale, "qt", "_", envTranslationFolder)) {
  189. p_app.installTranslator(qtEnvTranslator.take());
  190. }
  191. // Load translation for vnote from resource.
  192. QScopedPointer<QTranslator> vnoteTranslator(new QTranslator(&p_app));
  193. if (vnoteTranslator->load(locale, "vnote", "_", resourceTranslationFolder)) {
  194. p_app.installTranslator(vnoteTranslator.take());
  195. }
  196. // Load translation for vtextedit from resource.
  197. QScopedPointer<QTranslator> vtexteditTranslator(new QTranslator(&p_app));
  198. if (vtexteditTranslator->load(locale, "vtextedit", "_", resourceTranslationFolder)) {
  199. p_app.installTranslator(vtexteditTranslator.take());
  200. }
  201. }
  202. void initWebEngineSettings()
  203. {
  204. auto settings = QWebEngineSettings::defaultSettings();
  205. settings->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true);
  206. }
  207. void showMessageOnCommandLineIfAvailable(const QString &p_msg)
  208. {
  209. #if defined(Q_OS_WIN)
  210. MessageBoxHelper::notify(MessageBoxHelper::Information,
  211. QString("<pre>%1</pre>").arg(p_msg));
  212. #else
  213. fprintf(stderr, "%s\n", qPrintable(p_msg));
  214. #endif
  215. }