diff --git a/include/nana/gui/timer.hpp b/include/nana/gui/timer.hpp index 699be103..c360884b 100644 --- a/include/nana/gui/timer.hpp +++ b/include/nana/gui/timer.hpp @@ -22,14 +22,16 @@ namespace nana { - /// Can repeatedly call a piece of code. + + class timer; struct arg_elapse : public event_arg { - long long id; //timer identifier; + timer* sender; //indicates which timer emitted this notification }; + /// Can repeatedly call a piece of code. class timer { struct implement; diff --git a/source/detail/platform_spec_posix.cpp b/source/detail/platform_spec_posix.cpp index b0ef6c11..8944468b 100644 --- a/source/detail/platform_spec_posix.cpp +++ b/source/detail/platform_spec_posix.cpp @@ -210,15 +210,15 @@ namespace detail class timer_runner { - typedef void (*timer_proc_t)(std::size_t id); + using handler_type = void(*)(const timer_core*); struct timer_tag { - std::size_t id; - thread_t tid; + const timer_core* handle; + thread_t thread_id; std::size_t interval; std::size_t timestamp; - timer_proc_t proc; + handler_type handler; }; //timer_group @@ -234,32 +234,32 @@ namespace detail struct timer_group { bool proc_entered{false}; //This flag indicates whether the timers are going to do event. - std::set timers; - std::vector delay_deleted; + std::set timers; + std::vector delay_deleted; }; public: timer_runner() : is_proc_handling_(false) {} - void set(std::size_t id, std::size_t interval, timer_proc_t proc) + void set(const timer_core* handle, std::size_t interval, handler_type handler) { - auto i = holder_.find(id); + auto i = holder_.find(handle); if(i != holder_.end()) { i->second.interval = interval; - i->second.proc = proc; + i->second.handler = handler; return; } auto tid = nana::system::this_thread_id(); - threadmap_[tid].timers.insert(id); + threadmap_[tid].timers.insert(handle); - timer_tag & tag = holder_[id]; - tag.id = id; - tag.tid = tid; + timer_tag & tag = holder_[handle]; + tag.handle = handle; + tag.thread_id = tid; tag.interval = interval; tag.timestamp = 0; - tag.proc = proc; + tag.handler = handler; } bool is_proc_handling() const @@ -267,12 +267,12 @@ namespace detail return is_proc_handling_; } - void kill(std::size_t id) + bool kill(const timer_core* handle) { - auto i = holder_.find(id); + auto i = holder_.find(handle); if(i != holder_.end()) { - auto tid = i->second.tid; + auto tid = i->second.thread_id; auto ig = threadmap_.find(tid); if(ig != threadmap_.end()) //Generally, the ig should not be the end of threadmap_ @@ -280,20 +280,16 @@ namespace detail auto & group = ig->second; if(!group.proc_entered) { - group.timers.erase(id); + group.timers.erase(handle); if(group.timers.empty()) threadmap_.erase(ig); } else - group.delay_deleted.push_back(id); + group.delay_deleted.push_back(handle); } holder_.erase(i); } - } - - bool empty() const - { - return (holder_.empty()); + return holder_.empty(); } void timer_proc(thread_t tid) @@ -315,7 +311,7 @@ namespace detail tag.timestamp = ticks; try { - tag.proc(tag.id); + tag.handler(tag.handle); }catch(...){} //nothrow } } @@ -331,7 +327,7 @@ namespace detail private: bool is_proc_handling_; std::map threadmap_; - std::map holder_; + std::map holder_; }; drawable_impl_type::drawable_impl_type() @@ -439,7 +435,7 @@ namespace detail } platform_spec::timer_runner_tag::timer_runner_tag() - : runner(0), delete_declared(false) + : runner(nullptr), delete_declared(false) {} platform_spec::platform_spec() @@ -981,30 +977,32 @@ namespace detail return r; } - void platform_spec::set_timer(std::size_t id, std::size_t interval, void (*timer_proc)(std::size_t)) + void platform_spec::set_timer(const timer_core* handle, std::size_t interval, void (*timer_proc)(const timer_core*)) { std::lock_guard lock(timer_.mutex); - if(0 == timer_.runner) + if(!timer_.runner) timer_.runner = new timer_runner; - timer_.runner->set(id, interval, timer_proc); + + timer_.runner->set(handle, interval, timer_proc); timer_.delete_declared = false; } - void platform_spec::kill_timer(std::size_t id) + void platform_spec::kill_timer(const timer_core* handle) { - if(timer_.runner == 0) return; - std::lock_guard lock(timer_.mutex); - timer_.runner->kill(id); - if(timer_.runner->empty()) + if(timer_.runner) { - if(timer_.runner->is_proc_handling() == false) + // Test if there is not a timer after killing + if(timer_.runner->kill(handle)) { - delete timer_.runner; - timer_.runner = 0; + if(timer_.runner->is_proc_handling() == false) + { + delete timer_.runner; + timer_.runner = nullptr; + } + else + timer_.delete_declared = true; } - else - timer_.delete_declared = true; } } @@ -1017,7 +1015,7 @@ namespace detail if(timer_.delete_declared) { delete timer_.runner; - timer_.runner = 0; + timer_.runner = nullptr; timer_.delete_declared = false; } } diff --git a/source/detail/posix/platform_spec.hpp b/source/detail/posix/platform_spec.hpp index 83d91616..ff37717e 100644 --- a/source/detail/posix/platform_spec.hpp +++ b/source/detail/posix/platform_spec.hpp @@ -146,6 +146,13 @@ namespace detail //A forward declaration of caret data struct caret_rep; + /// class timer_core + /** + * Platform-spec only provides the declaration for intrducing a handle type, the definition + * of timer_core is given by gui/timer.cpp + */ + class timer_core; + class timer_runner; class platform_scope_guard @@ -226,8 +233,8 @@ namespace detail //when native_interface::show a window that is registered as a grab //window, the native_interface grabs the window. Window grab(Window); - void set_timer(std::size_t id, std::size_t interval, void (*timer_proc)(std::size_t id)); - void kill_timer(std::size_t id); + void set_timer(const timer_core*, std::size_t interval, void (*timer_proc)(const timer_core* tm)); + void kill_timer(const timer_core*); void timer_proc(thread_t tid); //Message dispatcher diff --git a/source/gui/msgbox.cpp b/source/gui/msgbox.cpp index 1c825da1..9d0467d0 100644 --- a/source/gui/msgbox.cpp +++ b/source/gui/msgbox.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include diff --git a/source/gui/timer.cpp b/source/gui/timer.cpp index 970aa5ab..8374a5fb 100644 --- a/source/gui/timer.cpp +++ b/source/gui/timer.cpp @@ -28,22 +28,26 @@ #if defined(NANA_WINDOWS) #include #elif defined(NANA_POSIX) -#include "../detail/platform_spec_selector.hpp" +#include "../detail/posix/platform_spec.hpp" #include #endif namespace nana { - class timer_core; + namespace detail + { + class timer_core; + } + #if defined(NANA_WINDOWS) typedef UINT_PTR timer_identifier; #else - typedef timer_core* timer_identifier; + typedef const detail::timer_core* timer_identifier; #endif class timer_driver { - friend class timer_core; + friend class detail::timer_core; timer_driver() = default; public: @@ -54,7 +58,7 @@ namespace nana } template - timer_core* create(unsigned ms, Factory && factory) + detail::timer_core* create(unsigned ms, Factory && factory) { #if defined(NANA_WINDOWS) auto tmid = ::SetTimer(nullptr, 0, ms, &timer_driver::_m_timer_proc); @@ -66,7 +70,7 @@ namespace nana #else auto p = factory(); auto tmid = p; - ::nana::detail::platform_spec::instance().set_timer(reinterpret_cast(tmid), ms, &timer_driver::_m_timer_proc); + ::nana::detail::platform_spec::instance().set_timer(tmid, ms, &timer_driver::_m_timer_proc); #endif ::nana::internal_scope_guard lock; timer_table_[tmid].reset(p); @@ -78,17 +82,17 @@ namespace nana return nullptr; } - void destroy(timer_identifier tid) + void destroy(timer_identifier handle) { ::nana::internal_scope_guard lock; - auto i = timer_table_.find(tid); + auto i = timer_table_.find(handle); if (i != timer_table_.end()) { #if defined(NANA_WINDOWS) - ::KillTimer(nullptr, tid); + ::KillTimer(nullptr, handle); #else - ::nana::detail::platform_spec::instance().kill_timer(reinterpret_cast(tid)); + ::nana::detail::platform_spec::instance().kill_timer(handle); #endif timer_table_.erase(i); } @@ -97,22 +101,26 @@ namespace nana #if defined(NANA_WINDOWS) static void __stdcall _m_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime); #else - static void _m_timer_proc(std::size_t id); + static void _m_timer_proc(timer_identifier id); #endif private: - std::map> timer_table_; + std::map> timer_table_; }; - class timer_core + class detail::timer_core { public: #if defined(NANA_WINDOWS) - timer_core(timer_identifier tmid, basic_event& evt_elapse) - : timer_(tmid), evt_elapse_(evt_elapse) + timer_core(timer* sender, timer_identifier tmid, basic_event& evt_elapse): + sender_(sender), + timer_(tmid), + evt_elapse_(evt_elapse) {} #else - timer_core(basic_event& evt_elapse) - : timer_(this), evt_elapse_(evt_elapse) + timer_core(timer* sender, basic_event& evt_elapse): + sender_(sender), + timer_(this), + evt_elapse_(evt_elapse) {} #endif @@ -126,43 +134,44 @@ namespace nana #if defined(NANA_WINDOWS) ::SetTimer(nullptr, timer_, ms, &timer_driver::_m_timer_proc); #else - ::nana::detail::platform_spec::instance().set_timer(reinterpret_cast(timer_), ms, &timer_driver::_m_timer_proc); + ::nana::detail::platform_spec::instance().set_timer(timer_, ms, &timer_driver::_m_timer_proc); #endif } - void emit(const arg_elapse& arg) + void emit() { + arg_elapse arg; + arg.sender = sender_; evt_elapse_.emit(arg, nullptr); } private: + timer * const sender_; const timer_identifier timer_; nana::basic_event & evt_elapse_; }; //end class timer_core #if defined(NANA_WINDOWS) - void __stdcall timer_driver::_m_timer_proc(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR id, DWORD /*dwTime*/) + void __stdcall timer_driver::_m_timer_proc(HWND /*hwnd*/, UINT /*uMsg*/, UINT_PTR handle, DWORD /*dwTime*/) #else - void timer_driver::_m_timer_proc(std::size_t id) + void timer_driver::_m_timer_proc(timer_identifier handle) #endif { auto & time_tbl = instance().timer_table_; ::nana::internal_scope_guard lock; - auto i = time_tbl.find(id); + auto i = time_tbl.find(handle); if (i == time_tbl.end()) return; - arg_elapse arg; - arg.id = id; - i->second->emit(arg); + i->second->emit(); } struct timer::implement { - unsigned interval = 1000; //Defaultly 1 second. - timer_core * tm_core = nullptr; + unsigned interval{ 1000 }; //1 second in default + detail::timer_core * tm_core{ nullptr }; }; //class timer @@ -196,12 +205,12 @@ namespace nana #if defined(NANA_WINDOWS) impl_->tm_core = timer_driver::instance().create(impl_->interval, [this](timer_identifier id) { - return new timer_core(id, elapse_); + return new detail::timer_core(this, id, elapse_); }); #else impl_->tm_core = timer_driver::instance().create(impl_->interval, [this] { - return new timer_core(elapse_); + return new detail::timer_core(this, elapse_); }); #endif }