146 lines
		
	
	
	
		
			2.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
	
		
			2.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| 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 <crl/crl_time.h>
 | |
| #include <crl/crl_object_on_queue.h>
 | |
| #include <QtCore/QThread>
 | |
| 
 | |
| namespace base {
 | |
| namespace details {
 | |
| 
 | |
| class TimerObject;
 | |
| 
 | |
| class TimerObjectWrap {
 | |
| public:
 | |
| 	explicit TimerObjectWrap(Fn<void()> adjust);
 | |
| 	~TimerObjectWrap();
 | |
| 
 | |
| 	void call(
 | |
| 		crl::time_type timeout,
 | |
| 		Qt::TimerType type,
 | |
| 		FnMut<void()> method);
 | |
| 	void cancel();
 | |
| 
 | |
| private:
 | |
| 	void sendEvent(std::unique_ptr<QEvent> event);
 | |
| 
 | |
| 	std::unique_ptr<TimerObject> _value;
 | |
| 
 | |
| };
 | |
| 
 | |
| } // namespace details
 | |
| 
 | |
| class ConcurrentTimerEnvironment {
 | |
| public:
 | |
| 	ConcurrentTimerEnvironment();
 | |
| 	~ConcurrentTimerEnvironment();
 | |
| 
 | |
| 	std::unique_ptr<details::TimerObject> createTimer(Fn<void()> adjust);
 | |
| 
 | |
| 	static void Adjust();
 | |
| 
 | |
| private:
 | |
| 	void acquire();
 | |
| 	void release();
 | |
| 	void adjustTimers();
 | |
| 
 | |
| 	QThread _thread;
 | |
| 	QObject _adjuster;
 | |
| 
 | |
| };
 | |
| 
 | |
| class ConcurrentTimer {
 | |
| public:
 | |
| 	explicit ConcurrentTimer(
 | |
| 		Fn<void(FnMut<void()>)> runner,
 | |
| 		Fn<void()> callback = nullptr);
 | |
| 
 | |
| 	template <typename Object>
 | |
| 	explicit ConcurrentTimer(
 | |
| 		crl::weak_on_queue<Object> weak,
 | |
| 		Fn<void()> callback = nullptr);
 | |
| 
 | |
| 	static Qt::TimerType DefaultType(TimeMs timeout) {
 | |
| 		constexpr auto kThreshold = TimeMs(1000);
 | |
| 		return (timeout > kThreshold) ? Qt::CoarseTimer : Qt::PreciseTimer;
 | |
| 	}
 | |
| 
 | |
| 	void setCallback(Fn<void()> callback) {
 | |
| 		_callback = std::move(callback);
 | |
| 	}
 | |
| 
 | |
| 	void callOnce(TimeMs timeout) {
 | |
| 		callOnce(timeout, DefaultType(timeout));
 | |
| 	}
 | |
| 
 | |
| 	void callEach(TimeMs timeout) {
 | |
| 		callEach(timeout, DefaultType(timeout));
 | |
| 	}
 | |
| 
 | |
| 	void callOnce(TimeMs timeout, Qt::TimerType type) {
 | |
| 		start(timeout, type, Repeat::SingleShot);
 | |
| 	}
 | |
| 
 | |
| 	void callEach(TimeMs timeout, Qt::TimerType type) {
 | |
| 		start(timeout, type, Repeat::Interval);
 | |
| 	}
 | |
| 
 | |
| 	bool isActive() const {
 | |
| 		return _running.alive();
 | |
| 	}
 | |
| 
 | |
| 	void cancel();
 | |
| 	TimeMs remainingTime() const;
 | |
| 
 | |
| private:
 | |
| 	enum class Repeat : unsigned {
 | |
| 		Interval = 0,
 | |
| 		SingleShot = 1,
 | |
| 	};
 | |
| 	Fn<void()> createAdjuster();
 | |
| 	void start(TimeMs timeout, Qt::TimerType type, Repeat repeat);
 | |
| 	void adjust();
 | |
| 
 | |
| 	void cancelAndSchedule(int timeout);
 | |
| 
 | |
| 	void setTimeout(TimeMs timeout);
 | |
| 	int timeout() const;
 | |
| 
 | |
| 	void timerEvent();
 | |
| 
 | |
| 	void setRepeat(Repeat repeat) {
 | |
| 		_repeat = static_cast<unsigned>(repeat);
 | |
| 	}
 | |
| 	Repeat repeat() const {
 | |
| 		return static_cast<Repeat>(_repeat);
 | |
| 	}
 | |
| 
 | |
| 	Fn<void(FnMut<void()>)> _runner;
 | |
| 	std::shared_ptr<bool> _guard; // Must be before _object.
 | |
| 	details::TimerObjectWrap _object;
 | |
| 	Fn<void()> _callback;
 | |
| 	base::binary_guard _running;
 | |
| 	TimeMs _next = 0;
 | |
| 	int _timeout = 0;
 | |
| 
 | |
| 	Qt::TimerType _type : 2;
 | |
| 	bool _adjusted : 1;
 | |
| 	unsigned _repeat : 1;
 | |
| 
 | |
| };
 | |
| 
 | |
| template <typename Object>
 | |
| ConcurrentTimer::ConcurrentTimer(
 | |
| 	crl::weak_on_queue<Object> weak,
 | |
| 	Fn<void()> callback)
 | |
| : ConcurrentTimer(weak.runner(), std::move(callback)) {
 | |
| }
 | |
| 
 | |
| } // namespace base
 | 
