|
1
|
1 #include "foobar2000-sdk-pch.h"
|
|
|
2 #include "foosort.h"
|
|
|
3 #include <functional>
|
|
|
4
|
|
|
5 namespace pfc {
|
|
|
6 /*
|
|
|
7 Redirect PFC methods to shared.dll
|
|
|
8 If you're getting linker multiple-definition errors on these, change build configuration of PFC from "Debug" / "Release" to "Debug FB2K" / "Release FB2K"
|
|
|
9 */
|
|
|
10 #ifdef _WIN32
|
|
|
11 BOOL winFormatSystemErrorMessageHook(pfc::string_base & p_out, DWORD p_code) {
|
|
|
12 return uFormatSystemErrorMessage(p_out, p_code);
|
|
|
13 }
|
|
|
14 #endif
|
|
|
15 void crashHook() {
|
|
|
16 uBugCheck();
|
|
|
17 }
|
|
|
18 }
|
|
|
19
|
|
|
20
|
|
|
21 // file_lock_manager.h functionality
|
|
|
22 #include "file_lock_manager.h"
|
|
|
23 namespace {
|
|
|
24 class file_lock_interrupt_impl : public file_lock_interrupt {
|
|
|
25 public:
|
|
|
26 void interrupt( abort_callback & a ) { f(a); }
|
|
|
27 std::function<void (abort_callback&)> f;
|
|
|
28 };
|
|
|
29 }
|
|
|
30
|
|
|
31 file_lock_interrupt::ptr file_lock_interrupt::create( std::function< void (abort_callback&)> f ) {
|
|
|
32 service_ptr_t<file_lock_interrupt_impl> i = new service_impl_t<file_lock_interrupt_impl>();
|
|
|
33 i->f = f;
|
|
|
34 return i;
|
|
|
35 }
|
|
|
36
|
|
|
37 // file_info_filter.h functionality
|
|
|
38 #include "file_info_filter.h"
|
|
|
39 namespace {
|
|
|
40 class file_info_filter_lambda : public file_info_filter {
|
|
|
41 public:
|
|
|
42 bool apply_filter(trackRef p_track,t_filestats p_stats,file_info & p_info) override {
|
|
|
43 return f(p_track, p_stats, p_info);
|
|
|
44 }
|
|
|
45 func_t f;
|
|
|
46 };
|
|
|
47 }
|
|
|
48
|
|
|
49 file_info_filter::ptr file_info_filter::create(func_t f) {
|
|
|
50 auto o = fb2k::service_new<file_info_filter_lambda>();
|
|
|
51 o->f = f;
|
|
|
52 return o;
|
|
|
53 }
|
|
|
54
|
|
|
55 // threadPool.h functionality
|
|
|
56 #include "threadPool.h"
|
|
|
57 namespace fb2k {
|
|
|
58 void inWorkerThread(std::function<void()> f) {
|
|
|
59 fb2k::splitTask(f);
|
|
|
60 }
|
|
|
61 void inCpuWorkerThread(std::function<void()> f) {
|
|
|
62 cpuThreadPool::get()->runSingle(threadEntry::make(f));
|
|
|
63 }
|
|
|
64 }
|
|
|
65 namespace {
|
|
|
66 class threadEntryImpl : public fb2k::threadEntry {
|
|
|
67 public:
|
|
|
68 void run() override { f(); }
|
|
|
69 std::function<void()> f;
|
|
|
70 };
|
|
|
71 }
|
|
|
72 namespace fb2k {
|
|
|
73 threadEntry::ptr threadEntry::make(std::function<void()> f) {
|
|
|
74 auto ret = fb2k::service_new<threadEntryImpl>();
|
|
|
75 ret->f = f;
|
|
|
76 return ret;
|
|
|
77 }
|
|
|
78
|
|
|
79 void cpuThreadPool::runMulti_(std::function<void()> f, size_t numRuns) {
|
|
|
80 this->runMulti(threadEntry::make(f), numRuns, true);
|
|
|
81 }
|
|
|
82
|
|
|
83 void cpuThreadPool::runMultiHelper(std::function<void()> f, size_t numRuns) {
|
|
|
84 if (numRuns == 0) return;
|
|
|
85 #if FOOBAR2000_TARGET_VERSION >= 81
|
|
|
86 get()->runMulti_(f, numRuns);
|
|
|
87 #else
|
|
|
88 if (numRuns == 1) {
|
|
|
89 f();
|
|
|
90 return;
|
|
|
91 }
|
|
|
92
|
|
|
93 size_t numThreads = numRuns - 1;
|
|
|
94 struct rec_t {
|
|
|
95 pfc::thread2 trd;
|
|
|
96 std::exception_ptr ex;
|
|
|
97 };
|
|
|
98 pfc::array_staticsize_t<rec_t> threads;
|
|
|
99 threads.set_size_discard(numThreads);
|
|
|
100 for (size_t walk = 0; walk < numThreads; ++walk) {
|
|
|
101 threads[walk].trd.startHere([f, &threads, walk] {
|
|
|
102 try {
|
|
|
103 f();
|
|
|
104 } catch (...) {
|
|
|
105 threads[walk].ex = std::current_exception();
|
|
|
106 }
|
|
|
107 });
|
|
|
108 }
|
|
|
109 std::exception_ptr exMain;
|
|
|
110 try {
|
|
|
111 f();
|
|
|
112 } catch (...) {
|
|
|
113 exMain = std::current_exception();
|
|
|
114 }
|
|
|
115
|
|
|
116 for (size_t walk = 0; walk < numThreads; ++walk) {
|
|
|
117 threads[walk].trd.waitTillDone();
|
|
|
118 }
|
|
|
119 if (exMain) std::rethrow_exception(exMain);
|
|
|
120 for (size_t walk = 0; walk < numThreads; ++walk) {
|
|
|
121 auto & ex = threads[walk].ex;
|
|
|
122 if (ex) std::rethrow_exception(ex);
|
|
|
123 }
|
|
|
124 #endif
|
|
|
125 }
|
|
|
126 }
|
|
|
127
|
|
|
128
|
|
|
129 #if FOOBAR2020
|
|
|
130 // timer.h functionality
|
|
|
131 #include "timer.h"
|
|
|
132 #include <memory>
|
|
|
133
|
|
|
134 namespace fb2k {
|
|
|
135 void callLater(double timeAfter, std::function< void() > func) {
|
|
|
136 PFC_ASSERT( core_api::is_main_thread() );
|
|
|
137 auto releaseMe = std::make_shared<objRef>();
|
|
|
138 *releaseMe = registerTimer(timeAfter, [=] {
|
|
|
139 if (releaseMe->is_valid()) { // ensure we get here once
|
|
|
140 func();
|
|
|
141 releaseMe->release(); // warning: this should destroy objects that called us, hence func() call must go first
|
|
|
142 }
|
|
|
143 });
|
|
|
144 }
|
|
|
145 objRef registerTimer(double interval, std::function<void()> func) {
|
|
|
146 PFC_ASSERT( core_api::is_main_thread() );
|
|
|
147 return static_api_ptr_t<timerManager>()->addTimer(interval, makeCompletionNotify([func](unsigned) { func(); }));
|
|
|
148 }
|
|
|
149 }
|
|
|
150 #endif // FOOBAR2020
|
|
|
151
|
|
|
152 // autoplaylist.h functionality
|
|
|
153 #include "autoplaylist.h"
|
|
|
154
|
|
|
155 bool autoplaylist_client::supports_async_() {
|
|
|
156 autoplaylist_client_v3::ptr v3;
|
|
|
157 bool rv = false;
|
|
|
158 if (v3 &= this) {
|
|
|
159 rv = v3->supports_async();
|
|
|
160 }
|
|
|
161 return rv;
|
|
|
162 }
|
|
|
163
|
|
|
164 bool autoplaylist_client::supports_get_contents_() {
|
|
|
165 autoplaylist_client_v3::ptr v3;
|
|
|
166 bool rv = false;
|
|
|
167 if (v3 &= this) {
|
|
|
168 rv = v3->supports_get_contents();
|
|
|
169 }
|
|
|
170 return rv;
|
|
|
171 }
|
|
|
172
|
|
|
173 void autoplaylist_client_v3::filter(metadb_handle_list_cref data, bool * out) {
|
|
|
174 filter_v2(data, nullptr, out, fb2k::noAbort);
|
|
|
175 }
|
|
|
176 bool autoplaylist_client_v3::sort(metadb_handle_list_cref p_items,t_size * p_orderbuffer) {
|
|
|
177 return sort_v2(p_items, p_orderbuffer, fb2k::noAbort);
|
|
|
178 }
|
|
|
179
|
|
|
180
|
|
|
181 #include "noInfo.h"
|
|
|
182 namespace fb2k {
|
|
|
183 noInfo_t noInfo;
|
|
|
184 }
|
|
|
185
|
|
|
186
|
|
|
187 // library_callbacks.h functionality
|
|
|
188 #include "library_callbacks.h"
|
|
|
189
|
|
|
190 bool library_callback::is_modified_from_hook() {
|
|
|
191 auto api = library_manager_v5::tryGet();
|
|
|
192 if (api.is_valid()) return api->library_status(library_manager_v5::status_current_callback_from_hook, 0, nullptr, 0) != 0;
|
|
|
193 else return false;
|
|
|
194 }
|
|
|
195
|
|
|
196 void library_callback_dynamic::register_callback() {
|
|
|
197 library_manager_v3::get()->register_callback(this);
|
|
|
198 }
|
|
|
199 void library_callback_dynamic::unregister_callback() {
|
|
|
200 library_manager_v3::get()->unregister_callback(this);
|
|
|
201 }
|
|
|
202
|
|
|
203 void library_callback_v2_dynamic::register_callback() {
|
|
|
204 library_manager_v4::get()->register_callback_v2(this);
|
|
|
205 }
|
|
|
206
|
|
|
207 void library_callback_v2_dynamic::unregister_callback() {
|
|
|
208 library_manager_v4::get()->unregister_callback_v2(this);
|
|
|
209 }
|
|
|
210
|
|
|
211
|
|
|
212
|
|
|
213 // configCache.h functionality
|
|
|
214 #include "configCache.h"
|
|
|
215 #include "configStore.h"
|
|
|
216
|
|
|
217 bool fb2k::configBoolCache::get() {
|
|
|
218 std::call_once(m_init, [this] {
|
|
|
219 auto api = fb2k::configStore::get();
|
|
|
220 auto refresh = [this, api] { m_value = api->getConfigBool(m_var, m_def); };
|
|
|
221 api->addPermanentNotify(m_var, refresh);
|
|
|
222 refresh();
|
|
|
223 });
|
|
|
224 return m_value;
|
|
|
225 }
|
|
|
226
|
|
|
227 int64_t fb2k::configIntCache::get() {
|
|
|
228 std::call_once(m_init, [this] {
|
|
|
229 auto api = fb2k::configStore::get();
|
|
|
230 auto refresh = [this, api] { m_value = api->getConfigInt(m_var, m_def); };
|
|
|
231 api->addPermanentNotify(m_var, refresh);
|
|
|
232 refresh();
|
|
|
233 });
|
|
|
234 return m_value;
|
|
|
235 }
|
|
|
236
|
|
|
237 void fb2k::configBoolCache::set(bool v) {
|
|
|
238 m_value = v;
|
|
|
239 fb2k::configStore::get()->setConfigBool(m_var, v);
|
|
|
240 }
|
|
|
241
|
|
|
242 void fb2k::configIntCache::set(int64_t v) {
|
|
|
243 m_value = v;
|
|
|
244 fb2k::configStore::get()->setConfigBool(m_var, v);
|
|
|
245 }
|
|
|
246
|
|
|
247
|
|
|
248 // keyValueIO.h functionality
|
|
|
249 #include "keyValueIO.h"
|
|
|
250
|
|
|
251 int fb2k::keyValueIO::getInt( const char * name ) {
|
|
|
252 auto str = get(name);
|
|
|
253 if ( str.is_empty() ) return 0;
|
|
|
254 return (int) pfc::atoi64_ex( str->c_str(), str->length() );
|
|
|
255 }
|
|
|
256
|
|
|
257 void fb2k::keyValueIO::putInt( const char * name, int val ) {
|
|
|
258 put( name, pfc::format_int(val) );
|
|
|
259 }
|
|
|
260
|
|
|
261
|
|
|
262 // fileDialog.h functionality
|
|
|
263 #include "fileDialog.h"
|
|
|
264 #include "fsitem.h"
|
|
|
265
|
|
|
266 namespace {
|
|
|
267 using namespace fb2k;
|
|
|
268 class fileDialogNotifyImpl : public fileDialogNotify {
|
|
|
269 public:
|
|
|
270 void dialogCancelled() {}
|
|
|
271 void dialogOK2(arrayRef fsItems) {
|
|
|
272 recv(fsItems);
|
|
|
273 }
|
|
|
274
|
|
|
275 std::function< void (arrayRef) > recv;
|
|
|
276 };
|
|
|
277 }
|
|
|
278
|
|
|
279 fb2k::fileDialogNotify::ptr fb2k::fileDialogNotify::create( std::function<void (arrayRef) > recv ) {
|
|
|
280 service_ptr_t<fileDialogNotifyImpl> obj = new service_impl_t< fileDialogNotifyImpl >();
|
|
|
281 obj->recv = recv;
|
|
|
282 return obj;
|
|
|
283 }
|
|
|
284
|
|
|
285 void fb2k::fileDialogSetup::run(fileDialogReply_t reply) {
|
|
|
286 this->run(fb2k::fileDialogNotify::create(reply));
|
|
|
287 }
|
|
|
288 void fb2k::fileDialogSetup::runSimple(fileDialogGetPath_t reply) {
|
|
|
289 fb2k::fileDialogReply_t wrapper = [reply] (fb2k::arrayRef arg) {
|
|
|
290 if ( arg.is_empty() ) {PFC_ASSERT(!"???"); return; }
|
|
|
291 if ( arg->size() != 1 ) { PFC_ASSERT(!"???"); return; }
|
|
|
292 auto obj = arg->itemAt(0);
|
|
|
293 fsItemBase::ptr fsitem;
|
|
|
294 if ( fsitem &= obj ) {
|
|
|
295 reply( fsitem->canonicalPath() ); return;
|
|
|
296 }
|
|
|
297 fb2k::stringRef str;
|
|
|
298 if ( str &= obj ) {
|
|
|
299 reply(str); return;
|
|
|
300 }
|
|
|
301 PFC_ASSERT( !"???" );
|
|
|
302 };
|
|
|
303 this->run(wrapper);
|
|
|
304 }
|
|
|
305
|
|
|
306 #include "input_file_type.h"
|
|
|
307
|
|
|
308 void fb2k::fileDialogSetup::setAudioFileTypes() {
|
|
|
309 pfc::string8 temp;
|
|
|
310 input_file_type::build_openfile_mask(temp);
|
|
|
311 this->setFileTypes( temp );
|
|
|
312 }
|
|
|
313
|
|
|
314
|
|
|
315 #include "search_tools.h"
|
|
|
316
|
|
|
317 void search_filter_v2::test_multi_here(metadb_handle_list& ref, abort_callback& abort) {
|
|
|
318 pfc::array_t<bool> mask; mask.resize(ref.get_size());
|
|
|
319 this->test_multi_ex(ref, mask.get_ptr(), abort);
|
|
|
320 ref.filter_mask(mask.get_ptr());
|
|
|
321 }
|
|
|
322
|
|
|
323
|
|
|
324
|
|
|
325 // core_api.h
|
|
|
326
|
|
|
327 namespace fb2k {
|
|
|
328 bool isDebugModeActive() {
|
|
|
329 #if PFC_DEBUG
|
|
|
330 return true;
|
|
|
331 #else
|
|
|
332 auto api = fb2k::configStore::tryGet();
|
|
|
333 if (api.is_empty()) return false;
|
|
|
334 return api->getConfigBool("core.debugMode");
|
|
|
335 #endif
|
|
|
336 }
|
|
|
337
|
|
|
338 #if FB2K_SUPPORT_LOW_MEM_MODE
|
|
|
339 static bool _isLowMemModeActive() {
|
|
|
340 auto api = fb2k::configStore::tryGet();
|
|
|
341 if (api.is_empty()) return false;
|
|
|
342 return api->getConfigBool("core.lowMemMode");
|
|
|
343 }
|
|
|
344
|
|
|
345 bool isLowMemModeActive() {
|
|
|
346 static bool cached = _isLowMemModeActive();
|
|
|
347 return cached;
|
|
|
348 }
|
|
|
349 #endif
|
|
|
350 }
|
|
|
351
|
|
|
352 // callback_merit.h
|
|
|
353 namespace fb2k {
|
|
|
354 callback_merit_t callback_merit_of(service_ptr obj) {
|
|
|
355 {
|
|
|
356 callback_with_merit::ptr q;
|
|
|
357 if (q &= obj) return q->get_callback_merit();
|
|
|
358 }
|
|
|
359 {
|
|
|
360 metadb_io_callback_v2::ptr q;
|
|
|
361 if (q &= obj) return q->get_callback_merit();
|
|
|
362 }
|
|
|
363 return callback_merit_default;
|
|
|
364 }
|
|
|
365 }
|
|
|
366
|
|
|
367 #ifdef _WIN32
|
|
|
368 #include "message_loop.h"
|
|
|
369 message_filter_impl_base::message_filter_impl_base() {
|
|
|
370 PFC_ASSERT( core_api::is_main_thread() );
|
|
|
371 message_loop::get()->add_message_filter(this);
|
|
|
372 }
|
|
|
373 message_filter_impl_base::message_filter_impl_base(t_uint32 lowest, t_uint32 highest) {
|
|
|
374 PFC_ASSERT( core_api::is_main_thread() );
|
|
|
375 message_loop_v2::get()->add_message_filter_ex(this, lowest, highest);
|
|
|
376 }
|
|
|
377 message_filter_impl_base::~message_filter_impl_base() {
|
|
|
378 PFC_ASSERT( core_api::is_main_thread() );
|
|
|
379 message_loop::get()->remove_message_filter(this);
|
|
|
380 }
|
|
|
381
|
|
|
382 bool message_filter_impl_accel::pretranslate_message(MSG * p_msg) {
|
|
|
383 if (m_wnd != NULL) {
|
|
|
384 if (GetActiveWindow() == m_wnd) {
|
|
|
385 if (TranslateAccelerator(m_wnd,m_accel.get(),p_msg) != 0) {
|
|
|
386 return true;
|
|
|
387 }
|
|
|
388 }
|
|
|
389 }
|
|
|
390 return false;
|
|
|
391 }
|
|
|
392
|
|
|
393 message_filter_impl_accel::message_filter_impl_accel(HINSTANCE p_instance,const TCHAR * p_accel) {
|
|
|
394 m_accel.load(p_instance,p_accel);
|
|
|
395 }
|
|
|
396
|
|
|
397 bool message_filter_remap_f1::pretranslate_message(MSG * p_msg) {
|
|
|
398 if (IsOurMsg(p_msg) && m_wnd != NULL && GetActiveWindow() == m_wnd) {
|
|
|
399 ::PostMessage(m_wnd, WM_SYSCOMMAND, SC_CONTEXTHELP, -1);
|
|
|
400 return true;
|
|
|
401 }
|
|
|
402 return false;
|
|
|
403 }
|
|
|
404
|
|
|
405 #endif
|