forked from quickshell/quickshell
		
	core/clock: fix instability causing timer to fire multiple times
If the signal was fired slightly before the scheduled time, it would schedule itself again a couple ms in the future.
This commit is contained in:
		
							parent
							
								
									a4903eaefc
								
							
						
					
					
						commit
						9555b201fe
					
				
					 2 changed files with 58 additions and 30 deletions
				
			
		| 
						 | 
					@ -8,7 +8,7 @@
 | 
				
			||||||
#include "util.hpp"
 | 
					#include "util.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SystemClock::SystemClock(QObject* parent): QObject(parent) {
 | 
					SystemClock::SystemClock(QObject* parent): QObject(parent) {
 | 
				
			||||||
	QObject::connect(&this->timer, &QTimer::timeout, this, &SystemClock::update);
 | 
						QObject::connect(&this->timer, &QTimer::timeout, this, &SystemClock::onTimeout);
 | 
				
			||||||
	this->update();
 | 
						this->update();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,41 +30,63 @@ void SystemClock::setPrecision(SystemClock::Enum precision) {
 | 
				
			||||||
	this->update();
 | 
						this->update();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SystemClock::onTimeout() {
 | 
				
			||||||
 | 
						this->setTime(this->nextTime);
 | 
				
			||||||
 | 
						this->schedule(this->nextTime);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SystemClock::update() {
 | 
					void SystemClock::update() {
 | 
				
			||||||
	auto time = QTime::currentTime();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (this->mEnabled) {
 | 
						if (this->mEnabled) {
 | 
				
			||||||
		auto secondPrecision = this->mPrecision >= SystemClock::Seconds;
 | 
							this->setTime(QTime::currentTime());
 | 
				
			||||||
		auto secondChanged = this->setSeconds(secondPrecision ? time.second() : 0);
 | 
							this->schedule(QTime::currentTime());
 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto minutePrecision = this->mPrecision >= SystemClock::Minutes;
 | 
					 | 
				
			||||||
		auto minuteChanged = this->setMinutes(minutePrecision ? time.minute() : 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto hourPrecision = this->mPrecision >= SystemClock::Hours;
 | 
					 | 
				
			||||||
		auto hourChanged = this->setHours(hourPrecision ? time.hour() : 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		DropEmitter::call(secondChanged, minuteChanged, hourChanged);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto nextTime = QTime(
 | 
					 | 
				
			||||||
		    hourPrecision ? time.hour() : 0,
 | 
					 | 
				
			||||||
		    minutePrecision ? time.minute() : 0,
 | 
					 | 
				
			||||||
		    secondPrecision ? time.second() : 0
 | 
					 | 
				
			||||||
		);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (secondPrecision) nextTime = nextTime.addSecs(1);
 | 
					 | 
				
			||||||
		else if (minutePrecision) nextTime = nextTime.addSecs(60);
 | 
					 | 
				
			||||||
		else if (hourPrecision) nextTime = nextTime.addSecs(3600);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto delay = time.msecsTo(nextTime);
 | 
					 | 
				
			||||||
		// day rollover
 | 
					 | 
				
			||||||
		if (delay < 0) delay += 86400000;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		this->timer.start(delay);
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		this->timer.stop();
 | 
							this->timer.stop();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SystemClock::setTime(QTime time) {
 | 
				
			||||||
 | 
						auto secondPrecision = this->mPrecision >= SystemClock::Seconds;
 | 
				
			||||||
 | 
						auto secondChanged = this->setSeconds(secondPrecision ? time.second() : 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto minutePrecision = this->mPrecision >= SystemClock::Minutes;
 | 
				
			||||||
 | 
						auto minuteChanged = this->setMinutes(minutePrecision ? time.minute() : 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto hourPrecision = this->mPrecision >= SystemClock::Hours;
 | 
				
			||||||
 | 
						auto hourChanged = this->setHours(hourPrecision ? time.hour() : 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						DropEmitter::call(secondChanged, minuteChanged, hourChanged);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SystemClock::schedule(QTime floor) {
 | 
				
			||||||
 | 
						auto secondPrecision = this->mPrecision >= SystemClock::Seconds;
 | 
				
			||||||
 | 
						auto minutePrecision = this->mPrecision >= SystemClock::Minutes;
 | 
				
			||||||
 | 
						auto hourPrecision = this->mPrecision >= SystemClock::Hours;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setnext:
 | 
				
			||||||
 | 
						auto nextTime = QTime(
 | 
				
			||||||
 | 
						    hourPrecision ? floor.hour() : 0,
 | 
				
			||||||
 | 
						    minutePrecision ? floor.minute() : 0,
 | 
				
			||||||
 | 
						    secondPrecision ? floor.second() : 0
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (secondPrecision) nextTime = nextTime.addSecs(1);
 | 
				
			||||||
 | 
						else if (minutePrecision) nextTime = nextTime.addSecs(60);
 | 
				
			||||||
 | 
						else if (hourPrecision) nextTime = nextTime.addSecs(3600);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto delay = QTime::currentTime().msecsTo(nextTime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If off by more than 2 hours we likely wrapped around midnight.
 | 
				
			||||||
 | 
						if (delay < -7200000) delay += 86400000;
 | 
				
			||||||
 | 
						else if (delay < 0) {
 | 
				
			||||||
 | 
							// Otherwise its just the timer being unstable.
 | 
				
			||||||
 | 
							floor = QTime::currentTime();
 | 
				
			||||||
 | 
							goto setnext;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->timer.start(delay);
 | 
				
			||||||
 | 
						this->nextTime = nextTime;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFINE_MEMBER_GETSET(SystemClock, hours, setHours);
 | 
					DEFINE_MEMBER_GETSET(SystemClock, hours, setHours);
 | 
				
			||||||
DEFINE_MEMBER_GETSET(SystemClock, minutes, setMinutes);
 | 
					DEFINE_MEMBER_GETSET(SystemClock, minutes, setMinutes);
 | 
				
			||||||
DEFINE_MEMBER_GETSET(SystemClock, seconds, setSeconds);
 | 
					DEFINE_MEMBER_GETSET(SystemClock, seconds, setSeconds);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <qdatetime.h>
 | 
				
			||||||
#include <qobject.h>
 | 
					#include <qobject.h>
 | 
				
			||||||
#include <qqmlintegration.h>
 | 
					#include <qqmlintegration.h>
 | 
				
			||||||
#include <qtimer.h>
 | 
					#include <qtimer.h>
 | 
				
			||||||
| 
						 | 
					@ -49,7 +50,7 @@ signals:
 | 
				
			||||||
	void secondsChanged();
 | 
						void secondsChanged();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private slots:
 | 
					private slots:
 | 
				
			||||||
	void update();
 | 
						void onTimeout();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	bool mEnabled = true;
 | 
						bool mEnabled = true;
 | 
				
			||||||
| 
						 | 
					@ -58,6 +59,11 @@ private:
 | 
				
			||||||
	quint32 mMinutes = 0;
 | 
						quint32 mMinutes = 0;
 | 
				
			||||||
	quint32 mSeconds = 0;
 | 
						quint32 mSeconds = 0;
 | 
				
			||||||
	QTimer timer;
 | 
						QTimer timer;
 | 
				
			||||||
 | 
						QTime nextTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void update();
 | 
				
			||||||
 | 
						void setTime(QTime time);
 | 
				
			||||||
 | 
						void schedule(QTime floor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DECLARE_PRIVATE_MEMBER(SystemClock, hours, setHours, mHours, hoursChanged);
 | 
						DECLARE_PRIVATE_MEMBER(SystemClock, hours, setHours, mHours, hoursChanged);
 | 
				
			||||||
	DECLARE_PRIVATE_MEMBER(SystemClock, minutes, setMinutes, mMinutes, minutesChanged);
 | 
						DECLARE_PRIVATE_MEMBER(SystemClock, minutes, setMinutes, mMinutes, minutesChanged);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue