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
 |