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 char path[PATH_MAX];
67 GBAConfigDirectory(path, sizeof(path));
68 VFile* vf = VFileDevice::open(QString::fromUtf8(path) + "/nointro.dat", O_RDONLY);
69 if (vf) {
70 m_db = NoIntroDBLoad(vf);
71 vf->close(vf);
72 }
73
74 if (!m_configController.getQtOption("audioDriver").isNull()) {
75 AudioProcessor::setDriver(static_cast<AudioProcessor::Driver>(m_configController.getQtOption("audioDriver").toInt()));
76 }
77 Window* w = new Window(&m_configController);
78 connect(w, &Window::destroyed, [this]() {
79 m_windows[0] = nullptr;
80 });
81 m_windows[0] = w;
82
83 if (loaded) {
84 w->argumentsPassed(&args);
85 } else {
86 w->loadConfig();
87 }
88 freeArguments(&args);
89
90 if (graphicsOpts.multiplier) {
91 w->resizeFrame(VIDEO_HORIZONTAL_PIXELS * graphicsOpts.multiplier, VIDEO_VERTICAL_PIXELS * graphicsOpts.multiplier);
92 }
93 if (graphicsOpts.fullscreen) {
94 w->enterFullScreen();
95 }
96
97 w->show();
98
99 w->controller()->setMultiplayerController(&m_multiplayer);
100 w->multiplayerChanged();
101}
102
103bool GBAApp::event(QEvent* event) {
104 if (event->type() == QEvent::FileOpen) {
105 m_windows[0]->controller()->loadGame(static_cast<QFileOpenEvent*>(event)->file());
106 return true;
107 }
108 return QApplication::event(event);
109}
110
111Window* GBAApp::newWindow() {
112 if (m_multiplayer.attached() >= MAX_GBAS) {
113 return nullptr;
114 }
115 Window* w = new Window(&m_configController, m_multiplayer.attached());
116 int windowId = m_multiplayer.attached();
117 connect(w, &Window::destroyed, [this, windowId]() {
118 m_windows[windowId] = nullptr;
119 });
120 m_windows[windowId] = w;
121 w->setAttribute(Qt::WA_DeleteOnClose);
122 w->loadConfig();
123 w->show();
124 w->controller()->setMultiplayerController(&m_multiplayer);
125 w->multiplayerChanged();
126 return w;
127}
128
129GBAApp* GBAApp::app() {
130 return g_app;
131}
132
133void GBAApp::interruptAll() {
134 for (int i = 0; i < MAX_GBAS; ++i) {
135 if (!m_windows[i] || !m_windows[i]->controller()->isLoaded()) {
136 continue;
137 }
138 m_windows[i]->controller()->threadInterrupt();
139 }
140}
141
142void GBAApp::continueAll() {
143 for (int i = 0; i < MAX_GBAS; ++i) {
144 if (!m_windows[i] || !m_windows[i]->controller()->isLoaded()) {
145 continue;
146 }
147 m_windows[i]->controller()->threadContinue();
148 }
149}
150
151QString GBAApp::getOpenFileName(QWidget* owner, const QString& title, const QString& filter) {
152 interruptAll();
153 QString filename = QFileDialog::getOpenFileName(owner, title, m_configController.getQtOption("lastDirectory").toString(), filter);
154 continueAll();
155 if (!filename.isEmpty()) {
156 m_configController.setQtOption("lastDirectory", QFileInfo(filename).dir().path());
157 }
158 return filename;
159}
160
161QString GBAApp::getSaveFileName(QWidget* owner, const QString& title, const QString& filter) {
162 interruptAll();
163 QString filename = QFileDialog::getSaveFileName(owner, title, m_configController.getQtOption("lastDirectory").toString(), filter);
164 continueAll();
165 if (!filename.isEmpty()) {
166 m_configController.setQtOption("lastDirectory", QFileInfo(filename).dir().path());
167 }
168 return filename;
169}
170
171QFileDialog* GBAApp::getOpenFileDialog(QWidget* owner, const QString& title, const QString& filter) {
172 FileDialog* dialog = new FileDialog(this, owner, title, filter);
173 dialog->setAcceptMode(QFileDialog::AcceptOpen);
174 return dialog;
175}
176
177QFileDialog* GBAApp::getSaveFileDialog(QWidget* owner, const QString& title, const QString& filter) {
178 FileDialog* dialog = new FileDialog(this, owner, title, filter);
179 dialog->setAcceptMode(QFileDialog::AcceptSave);
180 return dialog;
181}
182
183GBAApp::FileDialog::FileDialog(GBAApp* app, QWidget* parent, const QString& caption, const QString& filter)
184 : QFileDialog(parent, caption, app->m_configController.getQtOption("lastDirectory").toString(), filter)
185 , m_app(app)
186{
187}
188
189int GBAApp::FileDialog::exec() {
190 m_app->interruptAll();
191 bool didAccept = QFileDialog::exec() == QDialog::Accepted;
192 QStringList filenames = selectedFiles();
193 if (!filenames.isEmpty()) {
194 m_app->m_configController.setQtOption("lastDirectory", QFileInfo(filenames[0]).dir().path());
195 }
196 m_app->continueAll();
197 return didAccept;
198}