event.cpp (2058B)
1 /* ReaPack: Package manager for REAPER 2 * Copyright (C) 2015-2025 Christian Fillion 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include "event.hpp" 19 20 #include <reaper_plugin_functions.h> 21 22 static std::weak_ptr<AsyncEventImpl::Loop> s_loop; 23 24 AsyncEventImpl::Loop::Loop() 25 { 26 plugin_register("timer", reinterpret_cast<void *>(&mainThreadTimer)); 27 } 28 29 AsyncEventImpl::Loop::~Loop() 30 { 31 plugin_register("-timer", reinterpret_cast<void *>(&mainThreadTimer)); 32 } 33 34 void AsyncEventImpl::Loop::mainThreadTimer() 35 { 36 s_loop.lock()->processQueue(); 37 } 38 39 void AsyncEventImpl::Loop::push(const MainThreadFunc &event, const void *source) 40 { 41 std::lock_guard<std::mutex> guard(m_mutex); 42 m_queue.insert({source, event}); 43 } 44 45 void AsyncEventImpl::Loop::forget(const void *source) 46 { 47 std::lock_guard<std::mutex> guard(m_mutex); 48 m_queue.erase(source); 49 } 50 51 void AsyncEventImpl::Loop::processQueue() 52 { 53 decltype(m_queue) events; 54 55 { 56 std::lock_guard<std::mutex> guard(m_mutex); 57 std::swap(events, m_queue); 58 } 59 60 for(const auto &[emitter, func] : events) 61 func(), (void)emitter; 62 } 63 64 AsyncEventImpl::Emitter::Emitter() 65 { 66 if(s_loop.expired()) 67 s_loop = m_loop = std::make_shared<Loop>(); 68 else 69 m_loop = s_loop.lock(); 70 } 71 72 AsyncEventImpl::Emitter::~Emitter() 73 { 74 if(s_loop.use_count() > 1) 75 m_loop->forget(this); 76 } 77 78 void AsyncEventImpl::Emitter::runInMainThread(const MainThreadFunc &event) const 79 { 80 m_loop->push(event, this); 81 }