1 
2 
3 // Tnz6 includes
4 #include "mainwindow.h"
5 #include "flipbook.h"
6 #include "tapp.h"
7 #include "iocommand.h"
8 #include "previewfxmanager.h"
9 #include "cleanupsettingspopup.h"
10 #include "filebrowsermodel.h"
11 #include "expressionreferencemanager.h"
12 
13 // TnzTools includes
14 #include "tools/tool.h"
15 #include "tools/toolcommandids.h"
16 
17 // TnzQt includes
18 #include "toonzqt/dvdialog.h"
19 #include "toonzqt/menubarcommand.h"
20 #include "toonzqt/tmessageviewer.h"
21 #include "toonzqt/icongenerator.h"
22 #include "toonzqt/gutil.h"
23 #include "toonzqt/pluginloader.h"
24 
25 // TnzStdfx includes
26 #include "stdfx/shaderfx.h"
27 
28 // TnzLib includes
29 #include "toonz/preferences.h"
30 #include "toonz/toonzfolders.h"
31 #include "toonz/tproject.h"
32 #include "toonz/studiopalette.h"
33 #include "toonz/stylemanager.h"
34 #include "toonz/tscenehandle.h"
35 #include "toonz/txshsimplelevel.h"
36 #include "toonz/tproject.h"
37 #include "toonz/scriptengine.h"
38 
39 // TnzSound includes
40 #include "tnzsound.h"
41 
42 // TnzImage includes
43 #include "tnzimage.h"
44 
45 // TnzBase includes
46 #include "permissionsmanager.h"
47 #include "tenv.h"
48 #include "tcli.h"
49 
50 // TnzCore includes
51 #include "tsystem.h"
52 #include "tthread.h"
53 #include "tthreadmessage.h"
54 #include "tundo.h"
55 #include "tconvert.h"
56 #include "tiio_std.h"
57 #include "timagecache.h"
58 #include "tofflinegl.h"
59 #include "tpluginmanager.h"
60 #include "tsimplecolorstyles.h"
61 #include "toonz/imagestyles.h"
62 #include "tvectorbrushstyle.h"
63 #include "tfont.h"
64 
65 #include "kis_tablet_support_win8.h"
66 
67 #ifdef MACOSX
68 #include "tipc.h"
69 #endif
70 
71 // Qt includes
72 #include <QApplication>
73 #include <QAbstractEventDispatcher>
74 #include <QAbstractNativeEventFilter>
75 #include <QSplashScreen>
76 #include <QGLPixelBuffer>
77 #include <QTranslator>
78 #include <QFileInfo>
79 #include <QSettings>
80 #include <QLibraryInfo>
81 #include <QHash>
82 
83 #ifdef _WIN32
84 #ifndef x64
85 #include <float.h>
86 #endif
87 #include <QtPlatformHeaders/QWindowsWindowFunctions>
88 #endif
89 
90 using namespace DVGui;
91 
92 TEnv::IntVar EnvSoftwareCurrentFontSize("SoftwareCurrentFontSize", 12);
93 
94 const char *rootVarName     = "TOONZROOT";
95 const char *systemVarPrefix = "TOONZ";
96 
97 #ifdef MACOSX
98 #include "tthread.h"
postThreadMsg(TThread::Message *)99 void postThreadMsg(TThread::Message *) {}
100 void qt_mac_set_menubar_merge(bool enable);
101 #endif
102 
103 // Modifica per toonz (non servono questo tipo di licenze)
104 #define NO_LICENSE
105 //-----------------------------------------------------------------------------
106 
fatalError(QString msg)107 static void fatalError(QString msg) {
108   DVGui::MsgBoxInPopup(
109       CRITICAL,
110       msg + "\n" +
111           QObject::tr("Installing %1 again could fix the problem.")
112               .arg(QString::fromStdString(TEnv::getApplicationFullName())));
113   exit(0);
114 }
115 //-----------------------------------------------------------------------------
116 
lastWarningError(QString msg)117 static void lastWarningError(QString msg) {
118   DVGui::error(msg);
119   // exit(0);
120 }
121 //-----------------------------------------------------------------------------
122 
toonzRunOutOfContMemHandler(unsigned long size)123 static void toonzRunOutOfContMemHandler(unsigned long size) {
124 #ifdef _WIN32
125   static bool firstTime = true;
126   if (firstTime) {
127     MessageBox(NULL, (LPCWSTR)L"Run out of contiguous physical memory: please save all and restart Toonz!",
128 				   (LPCWSTR)L"Warning", MB_OK | MB_SYSTEMMODAL);
129     firstTime = false;
130   }
131 #endif
132 }
133 
134 //-----------------------------------------------------------------------------
135 
136 // todo.. da mettere in qualche .h
137 DV_IMPORT_API void initStdFx();
138 DV_IMPORT_API void initColorFx();
139 
140 //-----------------------------------------------------------------------------
141 
142 //! Inizializzaza l'Environment di Toonz
143 /*! In particolare imposta la projectRoot e
144     la stuffDir, controlla se la directory di outputs esiste (e provvede a
145     crearla in caso contrario) verifica inoltre che stuffDir esista.
146 */
initToonzEnv(QHash<QString,QString> & argPathValues)147 static void initToonzEnv(QHash<QString, QString> &argPathValues) {
148   StudioPalette::enable(true);
149   TEnv::setRootVarName(rootVarName);
150   TEnv::setSystemVarPrefix(systemVarPrefix);
151 
152   QHash<QString, QString>::const_iterator i = argPathValues.constBegin();
153   while (i != argPathValues.constEnd()) {
154     if (!TEnv::setArgPathValue(i.key().toStdString(), i.value().toStdString()))
155       DVGui::error(
156           QObject::tr("The qualifier %1 is not a valid key name. Skipping.")
157               .arg(i.key()));
158     ++i;
159   }
160 
161   QCoreApplication::setOrganizationName("OpenToonz");
162   QCoreApplication::setOrganizationDomain("");
163   QCoreApplication::setApplicationName(
164       QString::fromStdString(TEnv::getApplicationName()));
165 
166   /*-- TOONZROOTのPathの確認 --*/
167   // controllo se la xxxroot e' definita e corrisponde ad un folder esistente
168 
169   /*-- ENGLISH: Confirm TOONZROOT Path
170         Check if the xxxroot is defined and corresponds to an existing folder
171   --*/
172 
173   TFilePath stuffDir = TEnv::getStuffDir();
174   if (stuffDir == TFilePath())
175     fatalError("Undefined or empty: \"" + toQString(TEnv::getRootVarPath()) +
176                "\"");
177   else if (!TFileStatus(stuffDir).isDirectory())
178     fatalError("Folder \"" + toQString(stuffDir) +
179                "\" not found or not readable");
180 
181   Tiio::defineStd();
182   initImageIo();
183   initSoundIo();
184   initStdFx();
185   initColorFx();
186 
187   // TPluginManager::instance()->loadStandardPlugins();
188 
189   TFilePath library = ToonzFolder::getLibraryFolder();
190 
191   TRasterImagePatternStrokeStyle::setRootDir(library);
192   TVectorImagePatternStrokeStyle::setRootDir(library);
193   TVectorBrushStyle::setRootDir(library);
194 
195   CustomStyleManager::setRootPath(library);
196 
197   // sembra indispensabile nella lettura dei .tab 2.2:
198   TPalette::setRootDir(library);
199   TImageStyle::setLibraryDir(library);
200 
201   // TProjectManager::instance()->enableTabMode(true);
202 
203   TProjectManager *projectManager = TProjectManager::instance();
204 
205   /*--
206    * TOONZPROJECTSのパスセットを取得する。(TOONZPROJECTSはセミコロンで区切って複数設定可能)
207    * --*/
208   TFilePathSet projectsRoots = ToonzFolder::getProjectsFolders();
209   TFilePathSet::iterator it;
210   for (it = projectsRoots.begin(); it != projectsRoots.end(); ++it)
211     projectManager->addProjectsRoot(*it);
212 
213   /*-- もしまだ無ければ、TOONZROOT/sandboxにsandboxプロジェクトを作る --*/
214   projectManager->createSandboxIfNeeded();
215 
216   /*
217 TProjectP project = projectManager->getCurrentProject();
218 Non dovrebbe servire per Tab:
219 project->setFolder(TProject::Drawings, TFilePath("$scenepath"));
220 project->setFolder(TProject::Extras, TFilePath("$scenepath"));
221 project->setUseScenePath(TProject::Drawings, false);
222 project->setUseScenePath(TProject::Extras, false);
223 */
224   // Imposto la rootDir per ImageCache
225 
226   /*-- TOONZCACHEROOTの設定  --*/
227   TFilePath cacheDir = ToonzFolder::getCacheRootFolder();
228   if (cacheDir.isEmpty()) cacheDir = TEnv::getStuffDir() + "cache";
229   TImageCache::instance()->setRootDir(cacheDir);
230 }
231 
232 //-----------------------------------------------------------------------------
233 
script_output(int type,const QString & value)234 static void script_output(int type, const QString &value) {
235   if (type == ScriptEngine::ExecutionError ||
236       type == ScriptEngine::SyntaxError ||
237       type == ScriptEngine::UndefinedEvaluationResult ||
238       type == ScriptEngine::Warning)
239     std::cerr << value.toStdString() << std::endl;
240   else
241     std::cout << value.toStdString() << std::endl;
242 }
243 
244 //-----------------------------------------------------------------------------
245 
main(int argc,char * argv[])246 int main(int argc, char *argv[]) {
247 #ifdef Q_OS_WIN
248   //  Enable standard input/output on Windows Platform for debug
249   BOOL consoleAttached = ::AttachConsole(ATTACH_PARENT_PROCESS);
250   if (consoleAttached) {
251     freopen("CON", "r", stdin);
252     freopen("CON", "w", stdout);
253     freopen("CON", "w", stderr);
254   }
255 #endif
256 
257   // parsing arguments and qualifiers
258   TFilePath loadFilePath;
259   QString argumentLayoutFileName = "";
260   QHash<QString, QString> argumentPathValues;
261   if (argc > 1) {
262     TCli::Usage usage(argv[0]);
263     TCli::UsageLine usageLine;
264     TCli::FilePathArgument loadFileArg(
265         "filePath", "Source scene file to open or script file to run");
266     TCli::StringQualifier layoutFileQual(
267         "-layout filename",
268         "Custom layout file to be used, it should be saved in "
269         "$TOONZPROFILES\\layouts\\personal\\[CurrentLayoutName].[UserName]\\. "
270         "layouts.txt is used by default.");
271     usageLine = usageLine + layoutFileQual;
272 
273     // system path qualifiers
274     std::map<QString, std::unique_ptr<TCli::QualifierT<TFilePath>>>
275         systemPathQualMap;
276     QString qualKey  = QString("%1ROOT").arg(systemVarPrefix);
277     QString qualName = QString("-%1 folderpath").arg(qualKey);
278     QString qualHelp =
279         QString(
280             "%1 path. It will automatically set other system paths to %1 "
281             "unless individually specified with other qualifiers.")
282             .arg(qualKey);
283     systemPathQualMap[qualKey].reset(new TCli::QualifierT<TFilePath>(
284         qualName.toStdString(), qualHelp.toStdString()));
285     usageLine = usageLine + *systemPathQualMap[qualKey];
286 
287     const std::map<std::string, std::string> &spm = TEnv::getSystemPathMap();
288     for (auto itr = spm.begin(); itr != spm.end(); ++itr) {
289       qualKey = QString("%1%2")
290                     .arg(systemVarPrefix)
291                     .arg(QString::fromStdString((*itr).first));
292       qualName = QString("-%1 folderpath").arg(qualKey);
293       qualHelp = QString("%1 path.").arg(qualKey);
294       systemPathQualMap[qualKey].reset(new TCli::QualifierT<TFilePath>(
295           qualName.toStdString(), qualHelp.toStdString()));
296       usageLine = usageLine + *systemPathQualMap[qualKey];
297     }
298     usage.add(usageLine);
299     usage.add(usageLine + loadFileArg);
300 
301     if (!usage.parse(argc, argv)) exit(1);
302 
303     loadFilePath = loadFileArg.getValue();
304     if (layoutFileQual.isSelected())
305       argumentLayoutFileName =
306           QString::fromStdString(layoutFileQual.getValue());
307     for (auto q_itr = systemPathQualMap.begin();
308          q_itr != systemPathQualMap.end(); ++q_itr) {
309       if (q_itr->second->isSelected())
310         argumentPathValues.insert(q_itr->first,
311                                   q_itr->second->getValue().getQString());
312     }
313 
314     argc = 1;
315   }
316 
317 // Enables high-DPI scaling. This attribute must be set before QApplication is
318 // constructed. Available from Qt 5.6.
319 #if QT_VERSION >= 0x050600
320   QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
321 #endif
322 
323   QApplication a(argc, argv);
324 
325 #ifdef MACOSX
326   // This workaround is to avoid missing left button problem on Qt5.6.0.
327   // To invalidate m_rightButtonClicked in Qt/qnsview.mm, sending
328   // NSLeftButtonDown event before NSLeftMouseDragged event propagated to
329   // QApplication. See more details in ../mousedragfilter/mousedragfilter.mm.
330 
331 #include "mousedragfilter.h"
332 
333   class OSXMouseDragFilter final : public QAbstractNativeEventFilter {
334     bool leftButtonPressed = false;
335 
336   public:
337     bool nativeEventFilter(const QByteArray &eventType, void *message,
338                            long *) Q_DECL_OVERRIDE {
339       if (IsLeftMouseDown(message)) {
340         leftButtonPressed = true;
341       }
342       if (IsLeftMouseUp(message)) {
343         leftButtonPressed = false;
344       }
345 
346       if (eventType == "mac_generic_NSEvent") {
347         if (IsLeftMouseDragged(message) && !leftButtonPressed) {
348           std::cout << "force mouse press event" << std::endl;
349           SendLeftMousePressEvent();
350           return true;
351         }
352       }
353       return false;
354     }
355   };
356 
357   a.installNativeEventFilter(new OSXMouseDragFilter);
358 #endif
359 
360 #ifdef Q_OS_WIN
361   //	Since currently OpenToonz does not work with OpenGL of software or
362   // angle,	force Qt to use desktop OpenGL
363   // FIXME: This options should be called before constructing the application.
364   // Thus, ANGLE seems to be enabled as of now.
365   a.setAttribute(Qt::AA_UseDesktopOpenGL, true);
366 #endif
367 
368   // Some Qt objects are destroyed badly withouth a living qApp. So, we must
369   // enforce a way to either
370   // postpone the application destruction until the very end, OR ensure that
371   // sensible objects are
372   // destroyed before.
373 
374   // Using a static QApplication only worked on Windows, and in any case C++
375   // respects the statics destruction
376   // order ONLY within the same library. On MAC, it made the app crash on exit
377   // o_o. So, nope.
378 
379   std::unique_ptr<QObject> mainScope(new QObject(
380       &a));  // A QObject destroyed before the qApp is therefore explicitly
381   mainScope->setObjectName("mainScope");  // provided. It can be accessed by
382                                           // looking in the qApp's children.
383 
384 #ifdef _WIN32
385 #ifndef x64
386   // Store the floating point control word. It will be re-set before Toonz
387   // initialization
388   // has ended.
389   unsigned int fpWord = 0;
390   _controlfp_s(&fpWord, 0, 0);
391 #endif
392 #endif
393 
394 #ifdef _WIN32
395   // At least on windows, Qt's 4.5.2 native windows feature tend to create
396   // weird flickering effects when dragging panel separators.
397   a.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
398 #endif
399 
400   // Enable to render smooth icons on high dpi monitors
401   a.setAttribute(Qt::AA_UseHighDpiPixmaps);
402 #if defined(_WIN32) && QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
403   // Compress tablet events with application attributes instead of implementing
404   // the delay-timer by ourselves
405   a.setAttribute(Qt::AA_CompressHighFrequencyEvents);
406   a.setAttribute(Qt::AA_CompressTabletEvents);
407 #endif
408 
409 #ifdef _WIN32
410   // This attribute is set to make menubar icon to be always (16 x devPixRatio).
411   // Without this attribute the menu bar icon size becomes the same as tool bar
412   // when Windows scale is in 125%. Currently hiding the menu bar icon is done
413   // by setting transparent pixmap only in menu bar icon size. So the size must
414   // be different between for menu bar and for tool bar.
415   a.setAttribute(Qt::AA_Use96Dpi);
416 #endif
417 
418   // Set the app's locale for numeric stuff to standard C. This is important for
419   // atof() and similar
420   // calls that are locale-dependant.
421   setlocale(LC_NUMERIC, "C");
422 
423 // Set current directory to the bundle/application path - this is needed to have
424 // correct relative paths
425 #ifdef MACOSX
426   {
427     QDir appDir(QApplication::applicationDirPath());
428     appDir.cdUp(), appDir.cdUp(), appDir.cdUp();
429 
430     bool ret = QDir::setCurrent(appDir.absolutePath());
431     assert(ret);
432   }
433 #endif
434 
435   // Set icon theme search paths
436   QStringList themeSearchPathsList = {":/icons"};
437   QIcon::setThemeSearchPaths(themeSearchPathsList);
438   // qDebug() << "All icon theme search paths:" << QIcon::themeSearchPaths();
439 
440   // Set show icons in menus flag (use iconVisibleInMenu to disable selectively)
441   QApplication::instance()->setAttribute(Qt::AA_DontShowIconsInMenus, false);
442 
443   TEnv::setApplicationFileName(argv[0]);
444 
445   // splash screen
446   QPixmap splashPixmap = QIcon(":Resources/splash.svg").pixmap(QSize(610, 344));
447   splashPixmap.setDevicePixelRatio(QApplication::desktop()->devicePixelRatio());
448 // QPixmap splashPixmap(":Resources/splash.png");
449 #ifdef _WIN32
450   QFont font("Segoe UI", -1);
451 #else
452   QFont font("Helvetica", -1);
453 #endif
454   font.setPixelSize(13);
455   font.setWeight(50);
456   a.setFont(font);
457 
458   QString offsetStr("\n\n\n\n\n\n\n\n");
459 
460   TSystem::hasMainLoop(true);
461 
462   TMessageRepository::instance();
463 
464   bool isRunScript = (loadFilePath.getType() == "toonzscript");
465 
466   QSplashScreen splash(splashPixmap);
467   if (!isRunScript) splash.show();
468   a.processEvents();
469 
470   splash.showMessage(offsetStr + "Initializing QGLFormat...", Qt::AlignCenter,
471                      Qt::white);
472   a.processEvents();
473 
474   // OpenGL
475   QGLFormat fmt;
476   fmt.setAlpha(true);
477   fmt.setStencil(true);
478   QGLFormat::setDefaultFormat(fmt);
479 
480   glutInit(&argc, argv);
481 
482   splash.showMessage(offsetStr + "Initializing Toonz environment ...",
483                      Qt::AlignCenter, Qt::white);
484   a.processEvents();
485 
486   // Install run out of contiguous memory callback
487   TBigMemoryManager::instance()->setRunOutOfContiguousMemoryHandler(
488       &toonzRunOutOfContMemHandler);
489 
490   // Toonz environment
491   initToonzEnv(argumentPathValues);
492 
493   // Initialize thread components
494   TThread::init();
495 
496   TProjectManager *projectManager = TProjectManager::instance();
497   if (Preferences::instance()->isSVNEnabled()) {
498     // Read Version Control repositories and add it to project manager as
499     // "special" svn project root
500     VersionControl::instance()->init();
501     QList<SVNRepository> repositories =
502         VersionControl::instance()->getRepositories();
503     int count = repositories.size();
504     for (int i = 0; i < count; i++) {
505       SVNRepository r = repositories.at(i);
506 
507       TFilePath localPath(r.m_localPath.toStdWString());
508       if (!TFileStatus(localPath).doesExist()) {
509         try {
510           TSystem::mkDir(localPath);
511         } catch (TException &e) {
512           fatalError(QString::fromStdWString(e.getMessage()));
513         }
514       }
515       projectManager->addSVNProjectsRoot(localPath);
516     }
517   }
518 
519 #if defined(MACOSX) && defined(__LP64__)
520 
521   // Load the shared memory settings
522   int shmmax = Preferences::instance()->getShmMax();
523   int shmseg = Preferences::instance()->getShmSeg();
524   int shmall = Preferences::instance()->getShmAll();
525   int shmmni = Preferences::instance()->getShmMni();
526 
527   if (shmall <
528       0)  // Make sure that at least 100 MB of shared memory are available
529     shmall = (tipc::shm_maxSharedPages() < (100 << 8)) ? (100 << 8) : -1;
530 
531   tipc::shm_set(shmmax, shmseg, shmall, shmmni);
532 
533 #endif
534 
535   // DVDirModel must be instantiated after Version Control initialization...
536   FolderListenerManager::instance()->addListener(DvDirModel::instance());
537 
538   splash.showMessage(offsetStr + "Loading Translator ...", Qt::AlignCenter,
539                      Qt::white);
540   a.processEvents();
541 
542   // Carico la traduzione contenuta in toonz.qm (se � presente)
543   QString languagePathString =
544       QString::fromStdString(::to_string(TEnv::getConfigDir() + "loc"));
545 #ifndef WIN32
546   // the merge of menu on osx can cause problems with different languages with
547   // the Preferences menu
548   // qt_mac_set_menubar_merge(false);
549   languagePathString += "/" + Preferences::instance()->getCurrentLanguage();
550 #else
551   languagePathString += "\\" + Preferences::instance()->getCurrentLanguage();
552 #endif
553   QTranslator translator;
554   translator.load("toonz", languagePathString);
555 
556   // La installo
557   a.installTranslator(&translator);
558 
559   // Carico la traduzione contenuta in toonzqt.qm (se e' presente)
560   QTranslator translator2;
561   translator2.load("toonzqt", languagePathString);
562   a.installTranslator(&translator2);
563 
564   // Carico la traduzione contenuta in tnzcore.qm (se e' presente)
565   QTranslator tnzcoreTranslator;
566   tnzcoreTranslator.load("tnzcore", languagePathString);
567   qApp->installTranslator(&tnzcoreTranslator);
568 
569   // Carico la traduzione contenuta in toonzlib.qm (se e' presente)
570   QTranslator toonzlibTranslator;
571   toonzlibTranslator.load("toonzlib", languagePathString);
572   qApp->installTranslator(&toonzlibTranslator);
573 
574   // Carico la traduzione contenuta in colorfx.qm (se e' presente)
575   QTranslator colorfxTranslator;
576   colorfxTranslator.load("colorfx", languagePathString);
577   qApp->installTranslator(&colorfxTranslator);
578 
579   // Carico la traduzione contenuta in tools.qm
580   QTranslator toolTranslator;
581   toolTranslator.load("tnztools", languagePathString);
582   qApp->installTranslator(&toolTranslator);
583 
584   // load translation for file writers properties
585   QTranslator imageTranslator;
586   imageTranslator.load("image", languagePathString);
587   qApp->installTranslator(&imageTranslator);
588 
589   QTranslator qtTranslator;
590   qtTranslator.load("qt_" + QLocale::system().name(),
591                     QLibraryInfo::location(QLibraryInfo::TranslationsPath));
592   a.installTranslator(&qtTranslator);
593 
594   // Aggiorno la traduzione delle properties di tutti i tools
595   TTool::updateToolsPropertiesTranslation();
596   // Apply translation to file writers properties
597   Tiio::updateFileWritersPropertiesTranslation();
598 
599   // Force to have left-to-right layout direction in any language environment.
600   // This function has to be called after installTranslator().
601   a.setLayoutDirection(Qt::LeftToRight);
602 
603   splash.showMessage(offsetStr + "Loading styles ...", Qt::AlignCenter,
604                      Qt::white);
605   a.processEvents();
606 
607   // Set default start icon theme
608   QIcon::setThemeName(Preferences::instance()->getIconTheme() ? "dark"
609                                                               : "light");
610   // qDebug() << "Icon theme name:" << QIcon::themeName();
611 
612   // stile
613   QApplication::setStyle("windows");
614 
615   IconGenerator::setFilmstripIconSize(Preferences::instance()->getIconSize());
616 
617   splash.showMessage(offsetStr + "Loading shaders ...", Qt::AlignCenter,
618                      Qt::white);
619   a.processEvents();
620 
621   loadShaderInterfaces(ToonzFolder::getLibraryFolder() + TFilePath("shaders"));
622 
623   splash.showMessage(offsetStr + "Initializing OpenToonz ...", Qt::AlignCenter,
624                      Qt::white);
625   a.processEvents();
626 
627   TTool::setApplication(TApp::instance());
628   TApp::instance()->init();
629 
630   splash.showMessage(offsetStr + "Loading Plugins...", Qt::AlignCenter,
631                      Qt::white);
632   a.processEvents();
633   /* poll the thread ends:
634    絶対に必要なわけではないが PluginLoader は中で setup
635    ハンドラが常に固有のスレッドで呼ばれるよう main thread queue の blocking
636    をしているので
637    processEvents を行う必要がある
638 */
639   while (!PluginLoader::load_entries("")) {
640     a.processEvents();
641   }
642 
643   splash.showMessage(offsetStr + "Creating main window ...", Qt::AlignCenter,
644                      Qt::white);
645   a.processEvents();
646 
647   /*-- Layoutファイル名をMainWindowのctorに渡す --*/
648   MainWindow w(argumentLayoutFileName);
649 
650   if (isRunScript) {
651     // load script
652     if (TFileStatus(loadFilePath).doesExist()) {
653       // find project for this script file
654       TProjectManager *pm    = TProjectManager::instance();
655       TProjectP sceneProject = pm->loadSceneProject(loadFilePath);
656       TFilePath oldProjectPath;
657       if (!sceneProject) {
658         std::cerr << QObject::tr(
659                          "It is not possible to load the scene %1 because it "
660                          "does not "
661                          "belong to any project.")
662                          .arg(loadFilePath.getQString())
663                          .toStdString()
664                   << std::endl;
665         return 1;
666       }
667       if (sceneProject && !sceneProject->isCurrent()) {
668         oldProjectPath = pm->getCurrentProjectPath();
669         pm->setCurrentProjectPath(sceneProject->getProjectPath());
670       }
671       ScriptEngine engine;
672       QObject::connect(&engine, &ScriptEngine::output, script_output);
673       QString s = QString::fromStdWString(loadFilePath.getWideString())
674                       .replace("\\", "\\\\")
675                       .replace("\"", "\\\"");
676       QString cmd = QString("run(\"%1\")").arg(s);
677       engine.evaluate(cmd);
678       engine.wait();
679       if (!oldProjectPath.isEmpty()) pm->setCurrentProjectPath(oldProjectPath);
680       return 1;
681     } else {
682       std::cerr << QObject::tr("Script file %1 does not exists.")
683                        .arg(loadFilePath.getQString())
684                        .toStdString()
685                 << std::endl;
686       return 1;
687     }
688   }
689 
690 #ifdef _WIN32
691   // http://doc.qt.io/qt-5/windows-issues.html#fullscreen-opengl-based-windows
692   if (w.windowHandle())
693     QWindowsWindowFunctions::setHasBorderInFullScreen(w.windowHandle(), true);
694 #endif
695 
696     // Qt have started to support Windows Ink from 5.12.
697     // Unlike WinTab API used in Qt 5.9 the tablet behaviors are different and
698     // are (at least, for OT) problematic. The customized Qt5.15.2 are made with
699     // cherry-picking the WinTab feature to be officially introduced from 6.0.
700     // See https://github.com/shun-iwasawa/qt5/releases/tag/v5.15.2_wintab for
701     // details. The following feature can only be used with the customized Qt,
702     // with WITH_WINTAB build option, and in Windows-x64 build.
703 
704 #ifdef WITH_WINTAB
705   bool useQtNativeWinInk = Preferences::instance()->isQtNativeWinInkEnabled();
706   QWindowsWindowFunctions::setWinTabEnabled(!useQtNativeWinInk);
707 #endif
708 
709   splash.showMessage(offsetStr + "Loading style sheet ...", Qt::AlignCenter,
710                      Qt::white);
711   a.processEvents();
712 
713   // Carico lo styleSheet
714   QString currentStyle = Preferences::instance()->getCurrentStyleSheet();
715   a.setStyleSheet(currentStyle);
716 
717   w.setWindowTitle(QString::fromStdString(TEnv::getApplicationFullName()));
718   if (TEnv::getIsPortable()) {
719     splash.showMessage(offsetStr + "Starting OpenToonz Portable ...",
720                        Qt::AlignCenter, Qt::white);
721   } else {
722     splash.showMessage(offsetStr + "Starting main window ...", Qt::AlignCenter,
723                        Qt::white);
724   }
725   a.processEvents();
726 
727   TFilePath fp = ToonzFolder::getModuleFile("mainwindow.ini");
728   QSettings settings(toQString(fp), QSettings::IniFormat);
729   w.restoreGeometry(settings.value("MainWindowGeometry").toByteArray());
730 
731   ExpressionReferenceManager::instance()->init();
732 
733 #ifndef MACOSX
734   // Workaround for the maximized window case: Qt delivers two resize events,
735   // one in the normal geometry, before
736   // maximizing (why!?), the second afterwards - all inside the following show()
737   // call. This makes troublesome for
738   // the docking system to correctly restore the saved geometry. Fortunately,
739   // MainWindow::showEvent(..) gets called
740   // just between the two, so we can disable the currentRoom layout right before
741   // showing and re-enable it after
742   // the normal resize has happened.
743   if (w.isMaximized()) w.getCurrentRoom()->layout()->setEnabled(false);
744 #endif
745 
746   QRect splashGeometry = splash.geometry();
747   splash.finish(&w);
748 
749   a.setQuitOnLastWindowClosed(false);
750   // a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()));
751   if (Preferences::instance()->isLatestVersionCheckEnabled())
752     w.checkForUpdates();
753 
754   w.show();
755 
756   // Show floating panels only after the main window has been shown
757   w.startupFloatingPanels();
758 
759   CommandManager::instance()->execute(T_Hand);
760   if (!loadFilePath.isEmpty()) {
761     splash.showMessage(
762         QString("Loading file '") + loadFilePath.getQString() + "'...",
763         Qt::AlignCenter, Qt::white);
764     loadFilePath = loadFilePath.withType("tnz");
765     if (TFileStatus(loadFilePath).doesExist()) IoCmd::loadScene(loadFilePath);
766   }
767 
768   QFont *myFont;
769   QString fontName  = Preferences::instance()->getInterfaceFont();
770   QString fontStyle = Preferences::instance()->getInterfaceFontStyle();
771 
772   TFontManager *fontMgr = TFontManager::instance();
773   std::vector<std::wstring> typefaces;
774   bool isBold = false, isItalic = false, hasKerning = false;
775   try {
776     fontMgr->loadFontNames();
777     fontMgr->setFamily(fontName.toStdWString());
778     fontMgr->getAllTypefaces(typefaces);
779     isBold     = fontMgr->isBold(fontName, fontStyle);
780     isItalic   = fontMgr->isItalic(fontName, fontStyle);
781     hasKerning = fontMgr->hasKerning();
782   } catch (TFontCreationError &) {
783     // Do nothing. A default font should load
784   }
785 
786   myFont = new QFont(fontName);
787   myFont->setPixelSize(EnvSoftwareCurrentFontSize);
788   myFont->setBold(isBold);
789   myFont->setItalic(isItalic);
790   myFont->setKerning(hasKerning);
791 
792   a.setFont(*myFont);
793 
794   QAction *action = CommandManager::instance()->getAction("MI_OpenTMessage");
795   if (action)
796     QObject::connect(TMessageRepository::instance(),
797                      SIGNAL(openMessageCenter()), action, SLOT(trigger()));
798 
799   QObject::connect(TUndoManager::manager(), SIGNAL(somethingChanged()),
800                    TApp::instance()->getCurrentScene(), SLOT(setDirtyFlag()));
801 
802 #ifdef _WIN32
803 #ifndef x64
804   // On 32-bit architecture, there could be cases in which initialization could
805   // alter the
806   // FPU floating point control word. I've seen this happen when loading some
807   // AVI coded (VFAPI),
808   // where 80-bit internal precision was used instead of the standard 64-bit
809   // (much faster and
810   // sufficient - especially considering that x86 truncates to 64-bit
811   // representation anyway).
812   // IN ANY CASE, revert to the original control word.
813   // In the x64 case these precision changes simply should not take place up to
814   // _controlfp_s
815   // documentation.
816   _controlfp_s(0, fpWord, -1);
817 #endif
818 #endif
819 
820 #ifdef _WIN32
821   if (Preferences::instance()->isWinInkEnabled()) {
822     KisTabletSupportWin8 *penFilter = new KisTabletSupportWin8();
823     if (penFilter->init()) {
824       a.installNativeEventFilter(penFilter);
825     } else {
826       delete penFilter;
827     }
828   }
829 #endif
830 
831   a.installEventFilter(TApp::instance());
832 
833   int ret = a.exec();
834 
835   TUndoManager::manager()->reset();
836   PreviewFxManager::instance()->reset();
837 
838 #ifdef _WIN32
839   if (consoleAttached) {
840     ::FreeConsole();
841   }
842 #endif
843 
844   return ret;
845 }
846