/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "base/binary_guard.h" #include #include #include namespace base { namespace details { class TimerObject; class TimerObjectWrap { public: explicit TimerObjectWrap(Fn adjust); ~TimerObjectWrap(); void call( crl::time timeout, Qt::TimerType type, FnMut method); void cancel(); private: void sendEvent(std::unique_ptr event); std::unique_ptr _value; }; } // namespace details class ConcurrentTimerEnvironment { public: ConcurrentTimerEnvironment(); ~ConcurrentTimerEnvironment(); std::unique_ptr createTimer(Fn adjust); static void Adjust(); private: void acquire(); void release(); void adjustTimers(); QThread _thread; QObject _adjuster; }; class ConcurrentTimer { public: explicit ConcurrentTimer( Fn)> runner, Fn callback = nullptr); template explicit ConcurrentTimer( crl::weak_on_queue weak, Fn callback = nullptr); static Qt::TimerType DefaultType(crl::time timeout) { constexpr auto kThreshold = crl::time(1000); return (timeout > kThreshold) ? Qt::CoarseTimer : Qt::PreciseTimer; } void setCallback(Fn callback) { _callback = std::move(callback); } void callOnce(crl::time timeout) { callOnce(timeout, DefaultType(timeout)); } void callEach(crl::time timeout) { callEach(timeout, DefaultType(timeout)); } void callOnce(crl::time timeout, Qt::TimerType type) { start(timeout, type, Repeat::SingleShot); } void callEach(crl::time timeout, Qt::TimerType type) { start(timeout, type, Repeat::Interval); } bool isActive() const { return _running.alive(); } void cancel(); crl::time remainingTime() const; private: enum class Repeat : unsigned { Interval = 0, SingleShot = 1, }; Fn createAdjuster(); void start(crl::time timeout, Qt::TimerType type, Repeat repeat); void adjust(); void cancelAndSchedule(int timeout); void setTimeout(crl::time timeout); int timeout() const; void timerEvent(); void setRepeat(Repeat repeat) { _repeat = static_cast(repeat); } Repeat repeat() const { return static_cast(_repeat); } Fn)> _runner; std::shared_ptr _guard; // Must be before _object. details::TimerObjectWrap _object; Fn _callback; base::binary_guard _running; crl::time _next = 0; int _timeout = 0; Qt::TimerType _type : 2; bool _adjusted : 1; unsigned _repeat : 1; }; template ConcurrentTimer::ConcurrentTimer( crl::weak_on_queue weak, Fn callback) : ConcurrentTimer(weak.runner(), std::move(callback)) { } } // namespace base