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<GBAThread*>("GBAThread*");
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 GBAArguments args;
56 GraphicsOpts graphicsOpts;
57 SubParser 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::interruptAll() {
128 for (int i = 0; i < MAX_GBAS; ++i) {
129 if (!m_windows[i] || !m_windows[i]->controller()->isLoaded()) {
130 continue;
131 }
132 m_windows[i]->controller()->threadInterrupt();
133 }
134}
135
136void GBAApp::continueAll() {
137 for (int i = 0; i < MAX_GBAS; ++i) {
138 if (!m_windows[i] || !m_windows[i]->controller()->isLoaded()) {
139 continue;
140 }
141 m_windows[i]->controller()->threadContinue();
142 }
143}
144
145QString GBAApp::getOpenFileName(QWidget* owner, const QString& title, const QString& filter) {
146 interruptAll();
147 QString filename = QFileDialog::getOpenFileName(owner, title, m_configController.getQtOption("lastDirectory").toString(), filter);
148 continueAll();
149 if (!filename.isEmpty()) {
150 m_configController.setQtOption("lastDirectory", QFileInfo(filename).dir().path());
151 }
152 return filename;
153}
154
155QString GBAApp::getSaveFileName(QWidget* owner, const QString& title, const QString& filter) {
156 interruptAll();
157 QString filename = QFileDialog::getSaveFileName(owner, title, m_configController.getQtOption("lastDirectory").toString(), filter);
158 continueAll();
159 if (!filename.isEmpty()) {
160 m_configController.setQtOption("lastDirectory", QFileInfo(filename).dir().path());
161 }
162 return filename;
163}
164
165QFileDialog* GBAApp::getOpenFileDialog(QWidget* owner, const QString& title, const QString& filter) {
166 FileDialog* dialog = new FileDialog(this, owner, title, filter);
167 dialog->setAcceptMode(QFileDialog::AcceptOpen);
168 return dialog;
169}
170
171QFileDialog* GBAApp::getSaveFileDialog(QWidget* owner, const QString& title, const QString& filter) {
172 FileDialog* dialog = new FileDialog(this, owner, title, filter);
173 dialog->setAcceptMode(QFileDialog::AcceptSave);
174 return dialog;
175}
176
177bool GBAApp::reloadGameDB() {
178 NoIntroDB* db = nullptr;
179 char path[PATH_MAX];
180 GBAConfigDirectory(path, sizeof(path));
181 VFile* vf = VFileDevice::open(QString::fromUtf8(path) + "/nointro.dat", O_RDONLY);
182 if (vf) {
183 db = NoIntroDBLoad(vf);
184 vf->close(vf);
185 }
186 if (db && m_db) {
187 NoIntroDBDestroy(m_db);
188 }
189 m_db = db;
190}
191
192GBAApp::FileDialog::FileDialog(GBAApp* app, QWidget* parent, const QString& caption, const QString& filter)
193 : QFileDialog(parent, caption, app->m_configController.getQtOption("lastDirectory").toString(), filter)
194 , m_app(app)
195{
196}
197
198int GBAApp::FileDialog::exec() {
199 m_app->interruptAll();
200 bool didAccept = QFileDialog::exec() == QDialog::Accepted;
201 QStringList filenames = selectedFiles();
202 if (!filenames.isEmpty()) {
203 m_app->m_configController.setQtOption("lastDirectory", QFileInfo(filenames[0]).dir().path());
204 }
205 m_app->continueAll();
206 return didAccept;
207}