-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathEngineThread.cpp
More file actions
105 lines (90 loc) · 3.29 KB
/
EngineThread.cpp
File metadata and controls
105 lines (90 loc) · 3.29 KB
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
#include "EngineThread.h"
#include "ContainerWindow.h"
#include "Engine.h"
#include "EngineWindow.h"
#include "GLContext.h"
#include "utils.h"
void EngineThread::run() {
ThreadEntryPoint threadEntry("EngineThread");
CoInitializeScope com_enable{};
engineWindow.makeContextCurrent();
// We can only destroy the Engine while EngineThread is beeing destroyed,
// since mainthread callbacks held by EngineThread might reference Engine objects.
std::optional<Engine> engine;
try {
engine.emplace(*this, engineWindow, styleManager);
engine->mainLoop();
} catch (std::exception const& e) {
runInMainThread([msg = std::string{e.what()}, &container = engineWindow.container] {
container.destroyEngineWindow("Engine died with exception:\n" + msg);
// Note: destroyEngineWindow destroyes this EngineThread, `this` is invalid now
});
while (nullptr == dynamic_cast<EM::StopThread*>(messageQueue.pop().get())) {
// Going through the message queue has two purposes:
// 1. We wait for and find StopThread messages
// 2. We abandon any promises that are enqueued
}
}
}
void EngineThread::sendMessage(unique_ptr<engine_messages::Message>&& msg) {
messageQueue.push(std::move(msg));
}
EngineThread::EngineThread(EngineWindow& engineWindow, StyleManager& styleManager)
: engineWindow(engineWindow), styleManager(styleManager) {
instances.insert(this);
styleManager.setChangeHandler([&] { this->on_style_change(); });
play_callback_reregister(flag_on_playback_new_track, true);
std::packaged_task<void(EngineThread*)> task(&EngineThread::run);
thread = std::thread(std::move(task), this);
}
EngineThread::~EngineThread() {
instances.erase(this);
styleManager.setChangeHandler([] {});
this->send<EM::StopThread>();
// If the shutdown causes an exception, we need a second
// message to shut down the exception handler.
this->send<EM::StopThread>();
if (thread.joinable())
thread.join();
}
void EngineThread::invalidateWindow() {
RedrawWindow(engineWindow.hWnd, nullptr, nullptr, RDW_INVALIDATE);
}
std::unordered_set<EngineThread*> EngineThread::instances{};
void EngineThread::forEach(std::function<void(EngineThread&)> f) {
for (auto instance : instances) {
f(*instance);
}
}
void EngineThread::on_style_change() {
send<EM::TextFormatChangedMessage>();
invalidateWindow();
}
void EngineThread::on_playback_new_track(metadb_handle_ptr p_track) {
send<EM::PlaybackNewTrack>(p_track);
}
void EngineThread::on_items_added(metadb_handle_list_cref p_data) {
send<EM::LibraryItemsAdded>(p_data, libraryVersion);
}
void EngineThread::on_items_removed(metadb_handle_list_cref p_data) {
send<EM::LibraryItemsRemoved>(p_data, libraryVersion);
}
void EngineThread::on_items_modified(metadb_handle_list_cref p_data) {
send<EM::LibraryItemsModified>(p_data, libraryVersion);
}
void EngineThread::runInMainThread(std::function<void()> f) {
callbackHolder.addCallback(f);
}
CallbackHolder::CallbackHolder() : deadPtr(make_shared<bool>(false)) {}
CallbackHolder::~CallbackHolder() noexcept {
PFC_ASSERT(core_api::is_main_thread());
*deadPtr = true;
}
void CallbackHolder::addCallback(std::function<void()> f) {
fb2k::inMainThread([f, deadPtr = this->deadPtr] {
TRACK_CALL_TEXT("foo_chronflow::inMainThread");
if (!*deadPtr) {
f();
}
});
}