summaryrefslogtreecommitdiff
path: root/src/citra_qt/bootmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/citra_qt/bootmanager.cpp')
-rw-r--r--src/citra_qt/bootmanager.cpp310
1 files changed, 0 insertions, 310 deletions
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
deleted file mode 100644
index eb542ad4e..000000000
--- a/src/citra_qt/bootmanager.cpp
+++ /dev/null
@@ -1,310 +0,0 @@
1#include <QApplication>
2#include <QHBoxLayout>
3#include <QKeyEvent>
4
5#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
6// Required for screen DPI information
7#include <QScreen>
8#include <QWindow>
9#endif
10
11#include "citra_qt/bootmanager.h"
12#include "common/microprofile.h"
13#include "common/scm_rev.h"
14#include "common/string_util.h"
15#include "core/core.h"
16#include "core/frontend/framebuffer_layout.h"
17#include "core/settings.h"
18#include "input_common/keyboard.h"
19#include "input_common/main.h"
20#include "input_common/motion_emu.h"
21#include "network/network.h"
22
23EmuThread::EmuThread(GRenderWindow* render_window)
24 : exec_step(false), running(false), stop_run(false), render_window(render_window) {}
25
26void EmuThread::run() {
27 render_window->MakeCurrent();
28
29 MicroProfileOnThreadCreate("EmuThread");
30
31 stop_run = false;
32
33 // holds whether the cpu was running during the last iteration,
34 // so that the DebugModeLeft signal can be emitted before the
35 // next execution step
36 bool was_active = false;
37 while (!stop_run) {
38 if (running) {
39 if (!was_active)
40 emit DebugModeLeft();
41
42 Core::System::ResultStatus result = Core::System::GetInstance().RunLoop();
43 if (result != Core::System::ResultStatus::Success) {
44 emit ErrorThrown(result, Core::System::GetInstance().GetStatusDetails());
45 }
46
47 was_active = running || exec_step;
48 if (!was_active && !stop_run)
49 emit DebugModeEntered();
50 } else if (exec_step) {
51 if (!was_active)
52 emit DebugModeLeft();
53
54 exec_step = false;
55 Core::System::GetInstance().SingleStep();
56 emit DebugModeEntered();
57 yieldCurrentThread();
58
59 was_active = false;
60 } else {
61 std::unique_lock<std::mutex> lock(running_mutex);
62 running_cv.wait(lock, [this] { return IsRunning() || exec_step || stop_run; });
63 }
64 }
65
66 // Shutdown the core emulation
67 Core::System::GetInstance().Shutdown();
68
69#if MICROPROFILE_ENABLED
70 MicroProfileOnThreadExit();
71#endif
72
73 render_window->moveContext();
74}
75
76// This class overrides paintEvent and resizeEvent to prevent the GUI thread from stealing GL
77// context.
78// The corresponding functionality is handled in EmuThread instead
79class GGLWidgetInternal : public QGLWidget {
80public:
81 GGLWidgetInternal(QGLFormat fmt, GRenderWindow* parent)
82 : QGLWidget(fmt, parent), parent(parent) {}
83
84 void paintEvent(QPaintEvent* ev) override {
85 if (do_painting) {
86 QPainter painter(this);
87 }
88 }
89
90 void resizeEvent(QResizeEvent* ev) override {
91 parent->OnClientAreaResized(ev->size().width(), ev->size().height());
92 parent->OnFramebufferSizeChanged();
93 }
94
95 void DisablePainting() {
96 do_painting = false;
97 }
98 void EnablePainting() {
99 do_painting = true;
100 }
101
102private:
103 GRenderWindow* parent;
104 bool do_painting;
105};
106
107GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread)
108 : QWidget(parent), child(nullptr), emu_thread(emu_thread) {
109
110 std::string window_title = Common::StringFromFormat("Citra %s| %s-%s", Common::g_build_name,
111 Common::g_scm_branch, Common::g_scm_desc);
112 setWindowTitle(QString::fromStdString(window_title));
113
114 InputCommon::Init();
115 Network::Init();
116}
117
118GRenderWindow::~GRenderWindow() {
119 InputCommon::Shutdown();
120 Network::Shutdown();
121}
122
123void GRenderWindow::moveContext() {
124 DoneCurrent();
125// We need to move GL context to the swapping thread in Qt5
126#if QT_VERSION > QT_VERSION_CHECK(5, 0, 0)
127 // If the thread started running, move the GL Context to the new thread. Otherwise, move it
128 // back.
129 auto thread = (QThread::currentThread() == qApp->thread() && emu_thread != nullptr)
130 ? emu_thread
131 : qApp->thread();
132 child->context()->moveToThread(thread);
133#endif
134}
135
136void GRenderWindow::SwapBuffers() {
137#if !defined(QT_NO_DEBUG)
138 // Qt debug runtime prints a bogus warning on the console if you haven't called makeCurrent
139 // since the last time you called swapBuffers. This presumably means something if you're using
140 // QGLWidget the "regular" way, but in our multi-threaded use case is harmless since we never
141 // call doneCurrent in this thread.
142 child->makeCurrent();
143#endif
144 child->swapBuffers();
145}
146
147void GRenderWindow::MakeCurrent() {
148 child->makeCurrent();
149}
150
151void GRenderWindow::DoneCurrent() {
152 child->doneCurrent();
153}
154
155void GRenderWindow::PollEvents() {}
156
157// On Qt 5.0+, this correctly gets the size of the framebuffer (pixels).
158//
159// Older versions get the window size (density independent pixels),
160// and hence, do not support DPI scaling ("retina" displays).
161// The result will be a viewport that is smaller than the extent of the window.
162void GRenderWindow::OnFramebufferSizeChanged() {
163 // Screen changes potentially incur a change in screen DPI, hence we should update the
164 // framebuffer size
165 qreal pixelRatio = windowPixelRatio();
166 unsigned width = child->QPaintDevice::width() * pixelRatio;
167 unsigned height = child->QPaintDevice::height() * pixelRatio;
168 UpdateCurrentFramebufferLayout(width, height);
169}
170
171void GRenderWindow::BackupGeometry() {
172 geometry = ((QGLWidget*)this)->saveGeometry();
173}
174
175void GRenderWindow::RestoreGeometry() {
176 // We don't want to back up the geometry here (obviously)
177 QWidget::restoreGeometry(geometry);
178}
179
180void GRenderWindow::restoreGeometry(const QByteArray& geometry) {
181 // Make sure users of this class don't need to deal with backing up the geometry themselves
182 QWidget::restoreGeometry(geometry);
183 BackupGeometry();
184}
185
186QByteArray GRenderWindow::saveGeometry() {
187 // If we are a top-level widget, store the current geometry
188 // otherwise, store the last backup
189 if (parent() == nullptr)
190 return ((QGLWidget*)this)->saveGeometry();
191 else
192 return geometry;
193}
194
195qreal GRenderWindow::windowPixelRatio() {
196#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
197 // windowHandle() might not be accessible until the window is displayed to screen.
198 return windowHandle() ? windowHandle()->screen()->devicePixelRatio() : 1.0f;
199#else
200 return 1.0f;
201#endif
202}
203
204void GRenderWindow::closeEvent(QCloseEvent* event) {
205 emit Closed();
206 QWidget::closeEvent(event);
207}
208
209void GRenderWindow::keyPressEvent(QKeyEvent* event) {
210 InputCommon::GetKeyboard()->PressKey(event->key());
211}
212
213void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
214 InputCommon::GetKeyboard()->ReleaseKey(event->key());
215}
216
217void GRenderWindow::mousePressEvent(QMouseEvent* event) {
218 auto pos = event->pos();
219 if (event->button() == Qt::LeftButton) {
220 qreal pixelRatio = windowPixelRatio();
221 this->TouchPressed(static_cast<unsigned>(pos.x() * pixelRatio),
222 static_cast<unsigned>(pos.y() * pixelRatio));
223 } else if (event->button() == Qt::RightButton) {
224 InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y());
225 }
226}
227
228void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
229 auto pos = event->pos();
230 qreal pixelRatio = windowPixelRatio();
231 this->TouchMoved(std::max(static_cast<unsigned>(pos.x() * pixelRatio), 0u),
232 std::max(static_cast<unsigned>(pos.y() * pixelRatio), 0u));
233 InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y());
234}
235
236void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) {
237 if (event->button() == Qt::LeftButton)
238 this->TouchReleased();
239 else if (event->button() == Qt::RightButton)
240 InputCommon::GetMotionEmu()->EndTilt();
241}
242
243void GRenderWindow::focusOutEvent(QFocusEvent* event) {
244 QWidget::focusOutEvent(event);
245 InputCommon::GetKeyboard()->ReleaseAllKeys();
246}
247
248void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height) {
249 NotifyClientAreaSizeChanged(std::make_pair(width, height));
250}
251
252void GRenderWindow::InitRenderTarget() {
253 if (child) {
254 delete child;
255 }
256
257 if (layout()) {
258 delete layout();
259 }
260
261 // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
262 // WA_DontShowOnScreen, WA_DeleteOnClose
263 QGLFormat fmt;
264 fmt.setVersion(3, 3);
265 fmt.setProfile(QGLFormat::CoreProfile);
266 fmt.setSwapInterval(Settings::values.use_vsync);
267
268 // Requests a forward-compatible context, which is required to get a 3.2+ context on OS X
269 fmt.setOption(QGL::NoDeprecatedFunctions);
270
271 child = new GGLWidgetInternal(fmt, this);
272 QBoxLayout* layout = new QHBoxLayout(this);
273
274 resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height);
275 layout->addWidget(child);
276 layout->setMargin(0);
277 setLayout(layout);
278
279 OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
280
281 OnFramebufferSizeChanged();
282 NotifyClientAreaSizeChanged(std::pair<unsigned, unsigned>(child->width(), child->height()));
283
284 BackupGeometry();
285}
286
287void GRenderWindow::OnMinimalClientAreaChangeRequest(
288 const std::pair<unsigned, unsigned>& minimal_size) {
289 setMinimumSize(minimal_size.first, minimal_size.second);
290}
291
292void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread) {
293 this->emu_thread = emu_thread;
294 child->DisablePainting();
295}
296
297void GRenderWindow::OnEmulationStopping() {
298 emu_thread = nullptr;
299 child->EnablePainting();
300}
301
302void GRenderWindow::showEvent(QShowEvent* event) {
303 QWidget::showEvent(event);
304
305#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
306 // windowHandle() is not initialized until the Window is shown, so we connect it here.
307 connect(this->windowHandle(), SIGNAL(screenChanged(QScreen*)), this,
308 SLOT(OnFramebufferSizeChanged()), Qt::UniqueConnection);
309#endif
310}