summaryrefslogtreecommitdiffstats
path: root/dom/time/TimeChangeObserver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/time/TimeChangeObserver.cpp')
-rw-r--r--dom/time/TimeChangeObserver.cpp166
1 files changed, 166 insertions, 0 deletions
diff --git a/dom/time/TimeChangeObserver.cpp b/dom/time/TimeChangeObserver.cpp
new file mode 100644
index 000000000..8d002cfcd
--- /dev/null
+++ b/dom/time/TimeChangeObserver.cpp
@@ -0,0 +1,166 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "TimeChangeObserver.h"
+#include "mozilla/Hal.h"
+#include "mozilla/Observer.h"
+#include "mozilla/HalTypes.h"
+#include "nsWeakPtr.h"
+#include "nsTObserverArray.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/Services.h"
+#include "mozilla/StaticPtr.h"
+#include "nsPIDOMWindow.h"
+#include "nsContentUtils.h"
+#include "nsIObserverService.h"
+#include "nsIDocument.h"
+
+using namespace mozilla;
+using namespace mozilla::hal;
+using namespace mozilla::services;
+
+class nsSystemTimeChangeObserver : public SystemClockChangeObserver,
+ public SystemTimezoneChangeObserver
+{
+ typedef nsTObserverArray<nsWeakPtr> ListenerArray;
+public:
+ static nsSystemTimeChangeObserver* GetInstance();
+ virtual ~nsSystemTimeChangeObserver();
+
+ // Implementing hal::SystemClockChangeObserver::Notify()
+ void Notify(const int64_t& aClockDeltaMS);
+
+ // Implementing hal::SystemTimezoneChangeObserver::Notify()
+ void Notify(
+ const mozilla::hal::SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo);
+
+ nsresult AddWindowListenerImpl(nsPIDOMWindowInner* aWindow);
+ nsresult RemoveWindowListenerImpl(nsPIDOMWindowInner* aWindow);
+
+private:
+ nsSystemTimeChangeObserver() { };
+ ListenerArray mWindowListeners;
+ void FireMozTimeChangeEvent();
+};
+
+StaticAutoPtr<nsSystemTimeChangeObserver> sObserver;
+
+nsSystemTimeChangeObserver* nsSystemTimeChangeObserver::GetInstance()
+{
+ if (!sObserver) {
+ sObserver = new nsSystemTimeChangeObserver();
+ ClearOnShutdown(&sObserver);
+ }
+ return sObserver;
+}
+
+nsSystemTimeChangeObserver::~nsSystemTimeChangeObserver()
+{
+ UnregisterSystemClockChangeObserver(this);
+ UnregisterSystemTimezoneChangeObserver(this);
+}
+
+void
+nsSystemTimeChangeObserver::FireMozTimeChangeEvent()
+{
+ ListenerArray::ForwardIterator iter(mWindowListeners);
+ while (iter.HasMore()) {
+ nsWeakPtr weakWindow = iter.GetNext();
+ nsCOMPtr<nsPIDOMWindowInner> innerWindow = do_QueryReferent(weakWindow);
+ nsCOMPtr<nsPIDOMWindowOuter> outerWindow;
+ nsCOMPtr<nsIDocument> document;
+ if (!innerWindow ||
+ !(document = innerWindow->GetExtantDoc()) ||
+ !(outerWindow = innerWindow->GetOuterWindow())) {
+ mWindowListeners.RemoveElement(weakWindow);
+ continue;
+ }
+
+ nsContentUtils::DispatchTrustedEvent(document, outerWindow,
+ NS_LITERAL_STRING("moztimechange"), /* bubbles = */ true,
+ /* canceable = */ false);
+ }
+}
+
+void
+nsSystemTimeChangeObserver::Notify(const int64_t& aClockDeltaMS)
+{
+ // Notify observers that the system clock has been adjusted.
+ nsCOMPtr<nsIObserverService> observerService = GetObserverService();
+ if (observerService) {
+ nsString dataStr;
+ dataStr.AppendFloat(static_cast<double>(aClockDeltaMS));
+ observerService->NotifyObservers(
+ nullptr, "system-clock-change", dataStr.get());
+ }
+
+ FireMozTimeChangeEvent();
+}
+
+void
+nsSystemTimeChangeObserver::Notify(
+ const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
+{
+ FireMozTimeChangeEvent();
+}
+
+nsresult
+mozilla::time::AddWindowListener(nsPIDOMWindowInner* aWindow)
+{
+ return nsSystemTimeChangeObserver::GetInstance()->AddWindowListenerImpl(aWindow);
+}
+
+nsresult
+nsSystemTimeChangeObserver::AddWindowListenerImpl(nsPIDOMWindowInner* aWindow)
+{
+ if (!aWindow) {
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+
+ nsWeakPtr windowWeakRef = do_GetWeakReference(aWindow);
+ NS_ASSERTION(windowWeakRef, "nsIDOMWindow implementations shuld support weak ref");
+
+ if (mWindowListeners.IndexOf(windowWeakRef) !=
+ ListenerArray::array_type::NoIndex) {
+ return NS_OK;
+ }
+
+ if (mWindowListeners.IsEmpty()) {
+ RegisterSystemClockChangeObserver(sObserver);
+ RegisterSystemTimezoneChangeObserver(sObserver);
+ }
+
+ mWindowListeners.AppendElement(windowWeakRef);
+ return NS_OK;
+}
+
+nsresult
+mozilla::time::RemoveWindowListener(nsPIDOMWindowInner* aWindow)
+{
+ if (!sObserver) {
+ return NS_OK;
+ }
+
+ return nsSystemTimeChangeObserver::GetInstance()->RemoveWindowListenerImpl(aWindow);
+}
+
+nsresult
+nsSystemTimeChangeObserver::RemoveWindowListenerImpl(nsPIDOMWindowInner* aWindow)
+{
+ if (!aWindow) {
+ return NS_OK;
+ }
+
+ nsWeakPtr windowWeakRef = do_GetWeakReference(aWindow);
+ mWindowListeners.RemoveElement(windowWeakRef);
+
+ if (mWindowListeners.IsEmpty()) {
+ UnregisterSystemClockChangeObserver(sObserver);
+ UnregisterSystemTimezoneChangeObserver(sObserver);
+ }
+
+ return NS_OK;
+}