Vuo 2.4.4
Loading...
Searching...
No Matches
main.cc
Go to the documentation of this file.
1
10#include <getopt.h>
11#include <sys/stat.h>
12
13#define VUO_PCH_QT
14#include "../../vuo.pch"
15
16#include "VuoEditor.hh"
18#include "VuoEditorUtilities.hh"
19#include "VuoEditorWindow.hh"
20#include "VuoFileUtilities.hh"
21#include "VuoHeap.h"
22#include "VuoProtocol.hh"
23#include "VuoRendererCommon.hh"
24#include "VuoUrl.h"
25
26int main(int argc, char *argv[])
27{
28 // The content view of `VuoEditorWindow`s needs to be layer-backed instead of surface-backed to avoid glitchy
29 // rendering of the toolbar when transparent. However, setting `NSView.wantsLayer` in our code prevents the
30 // window content from rendering in Qt 5.12. So instead, have Qt set `wantsLayer` globally for all `NSView`s.
31 // (This should no longer be necessary in Qt 6, since there will no longer be surface-backed views.)
32 // https://b33p.net/kosada/vuo/vuo/-/issues/17855
33 // https://b33p.net/kosada/vuo/vuo/-/issues/13819
34 // https://bugreports.qt.io/browse/QTBUG-81370
35 qputenv("QT_MAC_WANTS_LAYER", "1");
36
37 // Qt 5.11 places compiled QML files (.qmlc) next to the QML source files,
38 // which breaks the app bundle's code signature.
39 // Making the app bundle's QML folders read-only
40 // causes Qt to place compiled QML files in ~/Library/Caches/Vuo/Editor/qmlcache.
41 // We make the app bundle's QML folders read-only when building the package,
42 // but some archive extractors (e.g. `The Unarchiver.app`) ignore this,
43 // so also ensure it at runtime.
44 // When we update to Qt 5.15 or later, we can use `QML_DISK_CACHE_PATH` instead.
45 // https://b33p.net/kosada/vuo/vuo/-/issues/17918
46 {
47 auto qmlDir = QFileInfo(argv[0]).absoluteDir();
48 qmlDir.cd("../qml");
49 chmod(qmlDir.absolutePath().toUtf8().data(), 0555);
50 QDirIterator qdi(qmlDir, QDirIterator::Subdirectories);
51 while (qdi.hasNext())
52 {
53 QFileInfo f(qdi.next());
54 if (!f.isDir() || f.fileName() == "." || f.fileName() == "..")
55 continue;
56 chmod(f.absoluteFilePath().toUtf8().data(), 0555);
57 }
58 }
59
60 qInstallMessageHandler(VuoRendererCommon::messageHandler);
61
62 Q_INIT_RESOURCE(VuoEditorApp);
63
64 bool doPrintHelp = false;
65 bool doOpenRecent = false;
66 bool doOpenRandom = false;
67 QString doOpenTemplate;
68 bool doRun = false;
69 bool doQuit = false;
70
71 int getoptArgC = 0;
72 char ** getoptArgV = (char **)malloc(sizeof(char *) * argc);
73 for(int i=0;i<argc;++i)
74 {
75 // Don't pass the OS X Process Serial Number argument to getopt, since it can't handle long arguments with a single hyphen.
76 if (strncmp(argv[i], "-psn_", 5) == 0)
77 continue;
78
79 // Don't pass single-hyphen (Qt-style) arguments to getopt, since it outputs warnings.
80 if (strlen(argv[i]) >= 2
81 && argv[i][0] == '-'
82 && argv[i][1] != '-')
83 continue;
84
85 getoptArgV[getoptArgC++] = argv[i];
86 }
87
88 static struct option options[] = {
89 {"help", no_argument, NULL, 0},
90 {"draw-bounding-rects", no_argument, NULL, 0},
91 {"generate-docs", required_argument, NULL, 0},
92 {"open-recent", no_argument, NULL, 0},
93 {"open-random", no_argument, NULL, 0},
94 {"run", no_argument, NULL, 0},
95 {"quit", no_argument, NULL, 0},
96 {"template", required_argument, NULL, 0},
97 {NULL, no_argument, NULL, 0}
98 };
99 int optionIndex=-1;
100 int ret;
101 while ((ret = getopt_long(getoptArgC, getoptArgV, "", options, &optionIndex)) != -1)
102 {
103 if (ret == '?')
104 continue;
105
106 switch(optionIndex)
107 {
108 case 0: // --help
109 doPrintHelp = true;
110 break;
111 case 1: // --draw-bounding-rects
113 break;
114 case 2: // --generate-docs
116 break;
117 case 3: // --open-recent
118 doOpenRecent = true;
119 break;
120 case 4: // --open-random
121 doOpenRandom = true;
122 break;
123 case 5: // --run
124 doRun = true;
125 break;
126 case 6: // --quit
127 doQuit = true;
128 break;
129 case 7: // --template
130 doOpenTemplate = optarg;
131 break;
132 default:
133 VUserLog("Error: Unknown option %d.", optionIndex);
134 break;
135 }
136 }
137
138 if (doPrintHelp)
139 {
140 free(getoptArgV);
141 printf("Usage: %s [options] [composition file(s)]\n"
142 "Options:\n"
143 " --help Display this information.\n"
144 " --draw-bounding-rects Draws red bounding rectangles around items in the composition canvas. Useful for debugging canvas interaction.\n"
145 " --generate-docs <dir> Saves the full collection of node class and node set documentation in <dir>, then exits.\n"
146 " --open-recent Reopens the most recent composition.\n"
147 " --open-random Opens a random example composition.\n"
148 " --template <template> Opens a new composition with the specified template.\n"
149 " E.g., \"--template VuoImageTransition\".\n"
150 " See Vuo.app/Contents/Frameworks/Vuo.framework/Resources/*.vuo for a full list.\n"
151 " --run Starts all open compositions running.\n"
152 " --quit Exits after optionally opening and running compositions. Useful for testing performance.\n",
153 argv[0]);
154 return 0;
155 }
156 else
157 {
158 // Tell Qt where to find its plugins.
159 QApplication::setLibraryPaths(QStringList((VuoFileUtilities::getVuoFrameworkPath() + "/../QtPlugins").c_str()));
160
161 // Qt's default cache is just 10 MB;
162 // caching pixmaps of 100 nodes (say, 200 * 150 * 4 pixels per Retina point * 4 bytes per pixel) uses 48 MB
163 // (and that doesn't even count cables, which have large bounding boxes).
164 QPixmapCache::setCacheLimit(512 * 1024);
165
166 VuoEditor v(argc,argv);
167
168 if (doOpenRecent)
169 v.openMostRecentFile();
170
171 if (doOpenRandom)
172 QTimer::singleShot(0, &v, &VuoEditor::openRandomExample);
173
174 if (!doOpenTemplate.isEmpty())
175 {
176 QAction *templateAction = new QAction(nullptr);
177
178 VuoProtocol *protocol = VuoProtocol::getProtocol(doOpenTemplate.toStdString());
179 if (protocol)
180 {
181 templateAction->setData(QVariant::fromValue(protocol));
182 QObject::connect(templateAction, &QAction::triggered, &v, &VuoEditor::newCompositionWithProtocol);
183 }
184 else
185 {
186 templateAction->setData(doOpenTemplate);
187 QObject::connect(templateAction, &QAction::triggered, &v, &VuoEditor::newCompositionWithTemplate);
188 }
189
190 QTimer::singleShot(0, templateAction, &QAction::trigger);
191 }
192
193 // If there are any arguments left over after getopt_long(), try to open them.
194 for (int i = optind; i < getoptArgC; ++i)
195 {
196 VuoText arg = VuoText_make(getoptArgV[i]);
197 VuoLocal(arg);
199 VuoLocal(u);
200 v.openUrl(u);
201 }
202
203 free(getoptArgV);
204
205 if (doRun)
206 QTimer::singleShot(0, ^{
208 {
210 // Wait for the composition to launch.
211 window->getComposition()->isRunning();
212 }
213 });
214
215 if (doQuit)
216 {
217 QTimer::singleShot(0, &v, &QApplication::closeAllWindows);
218 QTimer::singleShot(0, &v, &QApplication::quit);
219 }
220
221 return v.exec();
222 }
223}