src/platform/qt/GBAApp.cpp (view raw)
1/* Copyright (c) 2013-2014 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "GBAApp.h"
7
8#include "AudioProcessor.h"
9#include "Display.h"
10#include "GameController.h"
11#include "Window.h"
12#include "VFileDevice.h"
13
14#include <QFileInfo>
15#include <QFileOpenEvent>
16#include <QIcon>
17#include <QLibraryInfo>
18#include <QTranslator>
19
20#include <mgba/core/version.h>
21#include <mgba/internal/gba/video.h>
22#include <mgba-util/socket.h>
23#include <mgba-util/vfs.h>
24
25#ifdef USE_SQLITE3
26#include "feature/sqlite3/no-intro.h"
27#endif
28
29using namespace QGBA;
30
31static GBAApp* g_app = nullptr;
32
33mLOG_DEFINE_CATEGORY(QT, "Qt", "platform.qt");
34
35GBAApp::GBAApp(int& argc, char* argv[])
36 : QApplication(argc, argv)
37{
38 g_app = this;
39
40#ifdef BUILD_SDL
41 SDL_Init(SDL_INIT_NOPARACHUTE);
42#endif
43
44#ifndef Q_OS_MAC
45 setWindowIcon(QIcon(":/res/mgba-512.png"));
46#endif
47
48 QLocale locale;
49
50 if (!m_configController.getQtOption("language").isNull()) {
51 locale = QLocale(m_configController.getQtOption("language").toString());
52 }
53
54 QTranslator qtTranslator;
55 qtTranslator.load(locale, "qt", "_", QLibraryInfo::location(QLibraryInfo::TranslationsPath));
56 installTranslator(&qtTranslator);
57
58 QTranslator langTranslator;
59 langTranslator.load(locale, binaryName, "-", ":/translations/");
60 installTranslator(&langTranslator);
61
62 SocketSubsystemInit();
63 qRegisterMetaType<const uint32_t*>("const uint32_t*");
64 qRegisterMetaType<mCoreThread*>("mCoreThread*");
65
66 QApplication::setApplicationName(projectName);
67 QApplication::setApplicationVersion(projectVersion);
68
69 if (!m_configController.getQtOption("displayDriver").isNull()) {
70 Display::setDriver(static_cast<Display::Driver>(m_configController.getQtOption("displayDriver").toInt()));
71 }
72
73 mArguments args;
74 mGraphicsOpts graphicsOpts;
75 mSubParser subparser;
76 initParserForGraphics(&subparser, &graphicsOpts);
77 bool loaded = m_configController.parseArguments(&args, argc, argv, &subparser);
78 if (loaded && args.showHelp) {
79 usage(argv[0], subparser.usage);
80 ::exit(0);
81 return;
82 }
83
84 reloadGameDB();
85
86 if (!m_configController.getQtOption("audioDriver").isNull()) {
87 AudioProcessor::setDriver(static_cast<AudioProcessor::Driver>(m_configController.getQtOption("audioDriver").toInt()));
88 }
89 Window* w = new Window(&m_configController);
90 connect(w, &Window::destroyed, [this, w]() {
91 m_windows.removeAll(w);
92 });
93 m_windows.append(w);
94
95 if (loaded) {
96 w->argumentsPassed(&args);
97 } else {
98 w->loadConfig();
99 }
100 freeArguments(&args);
101
102 if (graphicsOpts.multiplier) {
103 w->resizeFrame(QSize(VIDEO_HORIZONTAL_PIXELS * graphicsOpts.multiplier, VIDEO_VERTICAL_PIXELS * graphicsOpts.multiplier));
104 }
105 if (graphicsOpts.fullscreen) {
106 w->enterFullScreen();
107 }
108
109 w->show();
110
111 w->controller()->setMultiplayerController(&m_multiplayer);
112 w->multiplayerChanged();
113}
114
115GBAApp::~GBAApp() {
116#ifdef USE_SQLITE3
117 m_parseThread.quit();
118 m_parseThread.wait();
119#endif
120}
121
122bool GBAApp::event(QEvent* event) {
123 if (event->type() == QEvent::FileOpen) {
124 m_windows[0]->controller()->loadGame(static_cast<QFileOpenEvent*>(event)->file());
125 return true;
126 }
127 return QApplication::event(event);
128}
129
130Window* GBAApp::newWindow() {
131 if (m_windows.count() >= MAX_GBAS) {
132 return nullptr;
133 }
134 Window* w = new Window(&m_configController, m_multiplayer.attached());
135 int windowId = m_multiplayer.attached();
136 connect(w, &Window::destroyed, [this, w]() {
137 m_windows.removeAll(w);
138 for (Window* w : m_windows) {
139 w->updateMultiplayerStatus(m_windows.count() < MAX_GBAS);
140 }
141 });
142 m_windows.append(w);
143 w->setAttribute(Qt::WA_DeleteOnClose);
144 w->loadConfig();
145 w->show();
146 w->controller()->setMultiplayerController(&m_multiplayer);
147 w->multiplayerChanged();
148 for (Window* w : m_windows) {
149 w->updateMultiplayerStatus(m_windows.count() < MAX_GBAS);
150 }
151 return w;
152}
153
154GBAApp* GBAApp::app() {
155 return g_app;
156}
157
158void GBAApp::pauseAll(QList<Window*>* paused) {
159 for (auto& window : m_windows) {
160 if (!window->controller()->isLoaded() || window->controller()->isPaused()) {
161 continue;
162 }
163 window->controller()->setPaused(true);
164 paused->append(window);
165 }
166}
167
168void GBAApp::continueAll(const QList<Window*>& paused) {
169 for (auto& window : paused) {
170 window->controller()->setPaused(false);
171 }
172}
173
174QString GBAApp::getOpenFileName(QWidget* owner, const QString& title, const QString& filter) {
175 QList<Window*> paused;
176 pauseAll(&paused);
177 QString filename = QFileDialog::getOpenFileName(owner, title, m_configController.getOption("lastDirectory"), filter);
178 continueAll(paused);
179 if (!filename.isEmpty()) {
180 m_configController.setOption("lastDirectory", QFileInfo(filename).dir().canonicalPath());
181 }
182 return filename;
183}
184
185QString GBAApp::getSaveFileName(QWidget* owner, const QString& title, const QString& filter) {
186 QList<Window*> paused;
187 pauseAll(&paused);
188 QString filename = QFileDialog::getSaveFileName(owner, title, m_configController.getOption("lastDirectory"), filter);
189 continueAll(paused);
190 if (!filename.isEmpty()) {
191 m_configController.setOption("lastDirectory", QFileInfo(filename).dir().canonicalPath());
192 }
193 return filename;
194}
195
196QString GBAApp::getOpenDirectoryName(QWidget* owner, const QString& title) {
197 QList<Window*> paused;
198 pauseAll(&paused);
199 QString filename = QFileDialog::getExistingDirectory(owner, title, m_configController.getOption("lastDirectory"));
200 continueAll(paused);
201 if (!filename.isEmpty()) {
202 m_configController.setOption("lastDirectory", QFileInfo(filename).dir().canonicalPath());
203 }
204 return filename;
205}
206
207QString GBAApp::dataDir() {
208#ifdef DATADIR
209 QString path = QString::fromUtf8(DATADIR);
210#else
211 QString path = QCoreApplication::applicationDirPath();
212#ifdef Q_OS_MAC
213 path += QLatin1String("/../Resources");
214#endif
215#endif
216 return path;
217}
218
219#ifdef USE_SQLITE3
220bool GBAApp::reloadGameDB() {
221 NoIntroDB* db = nullptr;
222 db = NoIntroDBLoad((ConfigController::configDir() + "/nointro.sqlite3").toUtf8().constData());
223 if (db && m_db) {
224 NoIntroDBDestroy(m_db);
225 }
226 if (db) {
227 if (m_parseThread.isRunning()) {
228 m_parseThread.quit();
229 m_parseThread.wait();
230 }
231 GameDBParser* parser = new GameDBParser(db);
232 m_parseThread.start();
233 parser->moveToThread(&m_parseThread);
234 QMetaObject::invokeMethod(parser, "parseNoIntroDB");
235 m_db = db;
236 return true;
237 }
238 return false;
239}
240#else
241bool GBAApp::reloadGameDB() {
242 return false;
243}
244#endif
245
246#ifdef USE_SQLITE3
247GameDBParser::GameDBParser(NoIntroDB* db, QObject* parent)
248 : QObject(parent)
249 , m_db(db)
250{
251 // Nothing to do
252}
253
254void GameDBParser::parseNoIntroDB() {
255 VFile* vf = VFileDevice::open(GBAApp::dataDir() + "/nointro.dat", O_RDONLY);
256 if (vf) {
257 NoIntroDBLoadClrMamePro(m_db, vf);
258 vf->close(vf);
259 }
260}
261
262#endif