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
18extern "C" {
19#include "gba/supervisor/thread.h"
20#include "platform/commandline.h"
21#include "util/nointro.h"
22#include "util/socket.h"
23}
24
25using namespace QGBA;
26
27static GBAApp* g_app = nullptr;
28
29GBAApp::GBAApp(int& argc, char* argv[])
30 : QApplication(argc, argv)
31 , m_windows{}
32 , m_db(nullptr)
33{
34 g_app = this;
35
36#ifdef BUILD_SDL
37 SDL_Init(SDL_INIT_NOPARACHUTE);
38#endif
39
40#ifndef Q_OS_MAC
41 setWindowIcon(QIcon(":/res/mgba-1024.png"));
42#endif
43
44 SocketSubsystemInit();
45 qRegisterMetaType<const uint32_t*>("const uint32_t*");
46 qRegisterMetaType<mCoreThread*>("mCoreThread*");
47
48 QApplication::setApplicationName(projectName);
49 QApplication::setApplicationVersion(projectVersion);
50
51 if (!m_configController.getQtOption("displayDriver").isNull()) {
52 Display::setDriver(static_cast<Display::Driver>(m_configController.getQtOption("displayDriver").toInt()));
53 }
54
55 mArguments args;
56 mGraphicsOpts graphicsOpts;
57 mSubParser subparser;
58 initParserForGraphics(&subparser, &graphicsOpts);
59 bool loaded = m_configController.parseArguments(&args, argc, argv, &subparser);
60 if (loaded && args.showHelp) {
61 usage(argv[0], subparser.usage);
62 ::exit(0);
63 return;
64 }
65
66 reloadGameDB();
67
68 if (!m_configController.getQtOption("audioDriver").isNull()) {
69 AudioProcessor::setDriver(static_cast<AudioProcessor::Driver>(m_configController.getQtOption("audioDriver").toInt()));
70 }
71 Window* w = new Window(&m_configController);
72 connect(w, &Window::destroyed, [this]() {
73 m_windows[0] = nullptr;
74 });
75 m_windows[0] = w;
76
77 if (loaded) {
78 w->argumentsPassed(&args);
79 } else {
80 w->loadConfig();
81 }
82 freeArguments(&args);
83
84 if (graphicsOpts.multiplier) {
85 w->resizeFrame(VIDEO_HORIZONTAL_PIXELS * graphicsOpts.multiplier, VIDEO_VERTICAL_PIXELS * graphicsOpts.multiplier);
86 }
87 if (graphicsOpts.fullscreen) {
88 w->enterFullScreen();
89 }
90
91 w->show();
92
93 w->controller()->setMultiplayerController(&m_multiplayer);
94 w->multiplayerChanged();
95}
96
97bool GBAApp::event(QEvent* event) {
98 if (event->type() == QEvent::FileOpen) {
99 m_windows[0]->controller()->loadGame(static_cast<QFileOpenEvent*>(event)->file());
100 return true;
101 }
102 return QApplication::event(event);
103}
104
105Window* GBAApp::newWindow() {
106 if (m_multiplayer.attached() >= MAX_GBAS) {
107 return nullptr;
108 }
109 Window* w = new Window(&m_configController, m_multiplayer.attached());
110 int windowId = m_multiplayer.attached();
111 connect(w, &Window::destroyed, [this, windowId]() {
112 m_windows[windowId] = nullptr;
113 });
114 m_windows[windowId] = w;
115 w->setAttribute(Qt::WA_DeleteOnClose);
116 w->loadConfig();
117 w->show();
118 w->controller()->setMultiplayerController(&m_multiplayer);
119 w->multiplayerChanged();
120 return w;
121}
122
123GBAApp* GBAApp::app() {
124 return g_app;
125}
126
127void GBAApp::pauseAll(QList<int>* paused) {
128 for (int i = 0; i < MAX_GBAS; ++i) {
129 if (!m_windows[i] || !m_windows[i]->controller()->isLoaded() || m_windows[i]->controller()->isPaused()) {
130 continue;
131 }
132 m_windows[i]->controller()->setPaused(true);
133 paused->append(i);
134 }
135}
136
137void GBAApp::continueAll(const QList<int>* paused) {
138 for (int i : *paused) {
139 m_windows[i]->controller()->setPaused(false);
140 }
141}
142
143QString GBAApp::getOpenFileName(QWidget* owner, const QString& title, const QString& filter) {
144 QList<int> paused;
145 pauseAll(&paused);
146 QString filename = QFileDialog::getOpenFileName(owner, title, m_configController.getQtOption("lastDirectory").toString(), filter);
147 continueAll(&paused);
148 if (!filename.isEmpty()) {
149 m_configController.setQtOption("lastDirectory", QFileInfo(filename).dir().path());
150 }
151 return filename;
152}
153
154QString GBAApp::getSaveFileName(QWidget* owner, const QString& title, const QString& filter) {
155 QList<int> paused;
156 pauseAll(&paused);
157 QString filename = QFileDialog::getSaveFileName(owner, title, m_configController.getQtOption("lastDirectory").toString(), filter);
158 continueAll(&paused);
159 if (!filename.isEmpty()) {
160 m_configController.setQtOption("lastDirectory", QFileInfo(filename).dir().path());
161 }
162 return filename;
163}
164
165QString GBAApp::getOpenDirectoryName(QWidget* owner, const QString& title) {
166 QList<int> paused;
167 pauseAll(&paused);
168 QString filename = QFileDialog::getExistingDirectory(owner, title, m_configController.getQtOption("lastDirectory").toString());
169 continueAll(&paused);
170 if (!filename.isEmpty()) {
171 m_configController.setQtOption("lastDirectory", QFileInfo(filename).dir().path());
172 }
173 return filename;
174}
175
176QFileDialog* GBAApp::getOpenFileDialog(QWidget* owner, const QString& title, const QString& filter) {
177 FileDialog* dialog = new FileDialog(this, owner, title, filter);
178 dialog->setAcceptMode(QFileDialog::AcceptOpen);
179 return dialog;
180}
181
182QFileDialog* GBAApp::getSaveFileDialog(QWidget* owner, const QString& title, const QString& filter) {
183 FileDialog* dialog = new FileDialog(this, owner, title, filter);
184 dialog->setAcceptMode(QFileDialog::AcceptSave);
185 return dialog;
186}
187
188QString GBAApp::dataDir() {
189#ifdef DATA_DIR
190 QString path = QString::fromUtf8(DATA_DIR);
191#else
192 QString path = QCoreApplication::applicationDirPath();
193#ifdef Q_OS_MAC
194 path += QLatin1String("/../Resources");
195#endif
196#endif
197 return path;
198}
199
200bool GBAApp::reloadGameDB() {
201 NoIntroDB* db = nullptr;
202 VFile* vf = VFileDevice::open(dataDir() + "/nointro.dat", O_RDONLY);
203 if (vf) {
204 db = NoIntroDBLoad(vf);
205 vf->close(vf);
206 }
207 if (db && m_db) {
208 NoIntroDBDestroy(m_db);
209 }
210 if (db) {
211 m_db = db;
212 return true;
213 }
214 return false;
215}
216
217GBAApp::FileDialog::FileDialog(GBAApp* app, QWidget* parent, const QString& caption, const QString& filter)
218 : QFileDialog(parent, caption, app->m_configController.getQtOption("lastDirectory").toString(), filter)
219 , m_app(app)
220{
221}
222
223int GBAApp::FileDialog::exec() {
224 QList<int> paused;
225 m_app->pauseAll(&paused);
226 bool didAccept = QFileDialog::exec() == QDialog::Accepted;
227 QStringList filenames = selectedFiles();
228 if (!filenames.isEmpty()) {
229 m_app->m_configController.setQtOption("lastDirectory", QFileInfo(filenames[0]).dir().path());
230 }
231 m_app->continueAll(&paused);
232 return didAccept;
233}