/*
* Copyright 2013 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* Authors:
* Charles Kerr
*/
#include
namespace unity {
namespace indicator {
namespace datetime {
class LiveClock::Impl
{
public:
Impl(LiveClock& owner, const std::shared_ptr& tzd):
owner_(owner),
timezones_(tzd)
{
if (timezones_)
{
timezones_->timezone.changed().connect ([this](const std::string& z) {setTimezone(z);});
setTimezone(timezones_->timezone.get());
}
owner_.skewTestIntervalSec.changed().connect([this](unsigned int intervalSec) {setInterval(intervalSec);});
setInterval(owner_.skewTestIntervalSec.get());
}
~Impl()
{
clearTimer();
g_clear_pointer (&timezone_, g_time_zone_unref);
}
GDateTime* localtime() const
{
g_assert (timezone_ != nullptr);
return g_date_time_new_now (timezone_);
}
private:
void setTimezone (const std::string& str)
{
g_clear_pointer (&timezone_, g_time_zone_unref);
timezone_= g_time_zone_new (str.c_str());
owner_.skewDetected();
}
private:
void clearTimer()
{
if (skew_timeout_id_)
{
g_source_remove(skew_timeout_id_);
skew_timeout_id_ = 0;
}
g_clear_pointer(&prev_datetime_, g_date_time_unref);
}
void setInterval(unsigned int seconds)
{
clearTimer();
if (seconds > 0)
{
prev_datetime_ = owner_.localtime();
skew_timeout_id_ = g_timeout_add_seconds(seconds, onTimerPulse, this);
}
}
static gboolean onTimerPulse(gpointer gself)
{
auto self = static_cast(gself);
// check to see if too much time passed since the last check */
GDateTime * now = self->owner_.localtime();
const GTimeSpan diff = g_date_time_difference(now, self->prev_datetime_);
const GTimeSpan fuzz = 5;
const GTimeSpan max = (self->owner_.skewTestIntervalSec.get() + fuzz) * G_USEC_PER_SEC;
if (abs(diff) > max)
self->owner_.skewDetected();
// update prev_datetime
g_clear_pointer(&self->prev_datetime_, g_date_time_unref);
self->prev_datetime_ = now;
return G_SOURCE_CONTINUE;
}
protected:
LiveClock& owner_;
GTimeZone * timezone_ = nullptr;
std::shared_ptr timezones_;
GDateTime * prev_datetime_ = nullptr;
unsigned int skew_timeout_id_ = 0;
unsigned int sleep_subscription_id_ = 0;
};
LiveClock::LiveClock(const std::shared_ptr& tzd):
p (new Impl (*this, tzd))
{
}
LiveClock::~LiveClock() =default;
GDateTime *
LiveClock::localtime() const
{
return p->localtime();
}
} // namespace datetime
} // namespace indicator
} // namespace unity