/*
* 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):
m_owner(owner),
m_timezones(tzd)
{
if (m_timezones)
{
m_timezones->timezone.changed().connect([this](const std::string& z) {setTimezone(z);});
setTimezone(m_timezones->timezone.get());
}
m_owner.skewTestIntervalSec.changed().connect([this](unsigned int intervalSec) {setInterval(intervalSec);});
setInterval(m_owner.skewTestIntervalSec.get());
}
~Impl()
{
clearTimer();
g_clear_pointer(&m_timezone, g_time_zone_unref);
}
DateTime localtime() const
{
g_assert(m_timezone != nullptr);
auto gdt = g_date_time_new_now(m_timezone);
DateTime ret(gdt);
g_date_time_unref(gdt);
return ret;
}
private:
void setTimezone(const std::string& str)
{
g_clear_pointer(&m_timezone, g_time_zone_unref);
m_timezone= g_time_zone_new(str.c_str());
m_owner.skewDetected();
}
private:
void clearTimer()
{
if (m_skew_timeout_id)
{
g_source_remove(m_skew_timeout_id);
m_skew_timeout_id = 0;
}
m_prev_datetime.reset();
}
void setInterval(unsigned int seconds)
{
clearTimer();
if (seconds > 0)
{
m_prev_datetime = localtime();
m_skew_timeout_id = g_timeout_add_seconds(seconds, onTimerPulse, this);
}
}
static gboolean onTimerPulse(gpointer gself)
{
static_cast(gself)->onTimerPulse();
return G_SOURCE_CONTINUE;
}
void onTimerPulse()
{
// check to see if too much time passed since the last check */
const auto now = localtime();
const auto diff = now.difference (m_prev_datetime);
const GTimeSpan fuzz = 5;
const GTimeSpan max = (m_owner.skewTestIntervalSec.get() + fuzz) * G_USEC_PER_SEC;
if (abs(diff) > max)
m_owner.skewDetected();
// check to see if the day has changed
if (now.day_of_year() != m_prev_datetime.day_of_year())
m_owner.dateChanged();
// update m_prev_datetime
m_prev_datetime = now;
}
protected:
LiveClock& m_owner;
GTimeZone * m_timezone = nullptr;
std::shared_ptr m_timezones;
DateTime m_prev_datetime;
unsigned int m_skew_timeout_id = 0;
};
LiveClock::LiveClock(const std::shared_ptr& tzd):
p(new Impl(*this, tzd))
{
}
LiveClock::~LiveClock() =default;
DateTime LiveClock::localtime() const
{
return p->localtime();
}
} // namespace datetime
} // namespace indicator
} // namespace unity