From 5ccf213171d4c03556361dcd2ecfbb4f3415a3c4 Mon Sep 17 00:00:00 2001 From: Takayama Fumihiko Date: Sat, 23 Sep 2023 19:17:35 +0900 Subject: [PATCH] Add monitor_manager --- .../frontmost_application_monitor/monitor.hpp | 19 ++++++- .../monitor_manager.hpp | 51 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 include/pqrs/osx/frontmost_application_monitor/monitor_manager.hpp diff --git a/include/pqrs/osx/frontmost_application_monitor/monitor.hpp b/include/pqrs/osx/frontmost_application_monitor/monitor.hpp index 0cd3a21..a4cbe9d 100644 --- a/include/pqrs/osx/frontmost_application_monitor/monitor.hpp +++ b/include/pqrs/osx/frontmost_application_monitor/monitor.hpp @@ -8,6 +8,7 @@ #include "application.hpp" #include "impl/impl.h" +#include "monitor_manager.hpp" #include #include @@ -25,12 +26,19 @@ class monitor final : public dispatcher::extra::dispatcher_client { monitor(const monitor&) = delete; monitor(std::weak_ptr weak_dispatcher) : dispatcher_client(weak_dispatcher) { + std::lock_guard guard(global_monitor_manager_mutex_); + + monitor_manager::get_global_monitor_manager()->insert(this); } virtual ~monitor(void) { + std::lock_guard guard(global_monitor_manager_mutex_); + detach_from_dispatcher([this] { stop(); }); + + monitor_manager::get_global_monitor_manager()->erase(this); } void async_start(void) { @@ -57,9 +65,16 @@ class monitor final : public dispatcher::extra::dispatcher_client { static void static_cpp_callback(const char* bundle_identifier, const char* file_path, void* context) { + std::lock_guard guard(global_monitor_manager_mutex_); + auto m = reinterpret_cast(context); if (m) { - m->cpp_callback(bundle_identifier, file_path); + // `static_cpp_callback` may be called even after the monitor instance has been deleted, + // so we need to check whether monitor is still alive. + if (monitor_manager::get_global_monitor_manager()->contains(m)) { + m->cpp_callback(bundle_identifier, + file_path); + } } } @@ -77,6 +92,8 @@ class monitor final : public dispatcher::extra::dispatcher_client { frontmost_application_changed(application_ptr); }); } + + static inline std::mutex global_monitor_manager_mutex_; }; } // namespace frontmost_application_monitor } // namespace osx diff --git a/include/pqrs/osx/frontmost_application_monitor/monitor_manager.hpp b/include/pqrs/osx/frontmost_application_monitor/monitor_manager.hpp new file mode 100644 index 0000000..577ffd7 --- /dev/null +++ b/include/pqrs/osx/frontmost_application_monitor/monitor_manager.hpp @@ -0,0 +1,51 @@ +#pragma once + +// (C) Copyright Takayama Fumihiko 2023. +// Distributed under the Boost Software License, Version 1.0. +// (See https://www.boost.org/LICENSE_1_0.txt) + +#include "application.hpp" +#include "impl/impl.h" +#include +#include + +namespace pqrs { +namespace osx { +namespace frontmost_application_monitor { +class monitor; + +// Manage valid frontmost_application_monitor::monitor instances with monitor_manager because +// the callbacks implemented in PQRSOSXFrontmostApplicationMonitor.swift are not cleanly consistent with the lifetime of monitor. +class monitor_manager final { +public: + static std::shared_ptr get_global_monitor_manager(void) { + if (!monitor_manager_) { + monitor_manager_ = std::make_shared(); + } + + return monitor_manager_; + } + + monitor_manager(void) { + } + + bool contains(const monitor* monitor_pointer) const { + return monitor_pointers_.contains(monitor_pointer); + } + + void insert(const monitor* monitor_pointer) { + monitor_pointers_.insert(monitor_pointer); + } + + void erase(const monitor* monitor_pointer) { + monitor_pointers_.erase(monitor_pointer); + } + +private: + static inline std::shared_ptr monitor_manager_; + + std::unordered_set monitor_pointers_; +}; +} // namespace frontmost_application_monitor +} // namespace osx +} // namespace pqrs