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