blob: 3eec1668e7876a3d4009d4b8d701e988ecef13f8 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
#include <atomic>
#include <QThread>
#include <QGLWidget>
#include "common/common.h"
#include "common/emu_window.h"
class QScreen;
class QKeyEvent;
class GRenderWindow;
class EmuThread : public QThread
{
Q_OBJECT
public:
/**
* Set image filename
*
* @param filename
* @warning Only call when not running!
*/
void SetFilename(std::string filename);
/**
* Start emulation (on new thread)
*
* @warning Only call when not running!
*/
void run() override;
/**
* Allow the CPU to process a single instruction (if cpu is not running)
*
* @note This function is thread-safe
*/
void ExecStep() { exec_cpu_step = true; }
/**
* Allow the CPU to continue processing instructions without interruption
*
* @note This function is thread-safe
*/
void SetCpuRunning(bool running) { cpu_running = running; }
/**
* Allow the CPU to continue processing instructions without interruption
*
* @note This function is thread-safe
*/
bool IsCpuRunning() { return cpu_running; }
public slots:
/**
* Stop emulation and wait for the thread to finish.
*
* @details: This function will wait a second for the thread to finish; if it hasn't finished until then, we'll terminate() it and wait another second, hoping that it will be terminated by then.
* @note: This function is thread-safe.
*/
void Stop();
private:
friend class GRenderWindow;
EmuThread(GRenderWindow* render_window);
std::string filename;
bool exec_cpu_step;
bool cpu_running;
std::atomic<bool> stop_run;
GRenderWindow* render_window;
signals:
/**
* Emitted when CPU when we've finished processing a single Gekko instruction
*
* @warning This will only be emitted when the CPU is not running (SetCpuRunning(false))
* @warning When connecting to this signal from other threads, make sure to specify either Qt::QueuedConnection (invoke slot within the destination object's message thread) or even Qt::BlockingQueuedConnection (additionally block source thread until slot returns)
*/
void CPUStepped();
};
class GRenderWindow : public QWidget, public EmuWindow
{
Q_OBJECT
public:
GRenderWindow(QWidget* parent = NULL);
~GRenderWindow();
void closeEvent(QCloseEvent*) override;
// EmuWindow implementation
void SwapBuffers() override;
void MakeCurrent() override;
void DoneCurrent() override;
void PollEvents() override;
void BackupGeometry();
void RestoreGeometry();
void restoreGeometry(const QByteArray& geometry); // overridden
QByteArray saveGeometry(); // overridden
EmuThread& GetEmuThread();
void keyPressEvent(QKeyEvent* event) override;
void keyReleaseEvent(QKeyEvent* event) override;
void ReloadSetKeymaps() override;
void OnClientAreaResized(unsigned width, unsigned height);
void OnFramebufferSizeChanged();
public slots:
void moveContext(); // overridden
private:
void OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) override;
QGLWidget* child;
EmuThread emu_thread;
QByteArray geometry;
/// Device id of keyboard for use with KeyMap
int keyboard_id;
};
|