Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "TimeChangeObserver.h"
8 : #include "mozilla/Hal.h"
9 : #include "mozilla/Observer.h"
10 : #include "mozilla/HalTypes.h"
11 : #include "nsWeakPtr.h"
12 : #include "nsTObserverArray.h"
13 : #include "mozilla/ClearOnShutdown.h"
14 : #include "mozilla/Services.h"
15 : #include "mozilla/StaticPtr.h"
16 : #include "nsPIDOMWindow.h"
17 : #include "nsContentUtils.h"
18 : #include "nsIObserverService.h"
19 : #include "nsIDocument.h"
20 :
21 : using namespace mozilla;
22 : using namespace mozilla::hal;
23 : using namespace mozilla::services;
24 :
25 : class nsSystemTimeChangeObserver : public SystemClockChangeObserver,
26 : public SystemTimezoneChangeObserver
27 : {
28 : typedef nsTObserverArray<nsWeakPtr> ListenerArray;
29 : public:
30 : static nsSystemTimeChangeObserver* GetInstance();
31 : virtual ~nsSystemTimeChangeObserver();
32 :
33 : // Implementing hal::SystemClockChangeObserver::Notify()
34 : void Notify(const int64_t& aClockDeltaMS);
35 :
36 : // Implementing hal::SystemTimezoneChangeObserver::Notify()
37 : void Notify(
38 : const mozilla::hal::SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo);
39 :
40 : nsresult AddWindowListenerImpl(nsPIDOMWindowInner* aWindow);
41 : nsresult RemoveWindowListenerImpl(nsPIDOMWindowInner* aWindow);
42 :
43 : private:
44 0 : nsSystemTimeChangeObserver() { };
45 : ListenerArray mWindowListeners;
46 : void FireMozTimeChangeEvent();
47 : };
48 :
49 3 : StaticAutoPtr<nsSystemTimeChangeObserver> sObserver;
50 :
51 0 : nsSystemTimeChangeObserver* nsSystemTimeChangeObserver::GetInstance()
52 : {
53 0 : if (!sObserver) {
54 0 : sObserver = new nsSystemTimeChangeObserver();
55 0 : ClearOnShutdown(&sObserver);
56 : }
57 0 : return sObserver;
58 : }
59 :
60 0 : nsSystemTimeChangeObserver::~nsSystemTimeChangeObserver()
61 : {
62 0 : UnregisterSystemClockChangeObserver(this);
63 0 : UnregisterSystemTimezoneChangeObserver(this);
64 0 : }
65 :
66 : void
67 0 : nsSystemTimeChangeObserver::FireMozTimeChangeEvent()
68 : {
69 0 : ListenerArray::ForwardIterator iter(mWindowListeners);
70 0 : while (iter.HasMore()) {
71 0 : nsWeakPtr weakWindow = iter.GetNext();
72 0 : nsCOMPtr<nsPIDOMWindowInner> innerWindow = do_QueryReferent(weakWindow);
73 0 : nsCOMPtr<nsPIDOMWindowOuter> outerWindow;
74 0 : nsCOMPtr<nsIDocument> document;
75 0 : if (!innerWindow ||
76 0 : !(document = innerWindow->GetExtantDoc()) ||
77 0 : !(outerWindow = innerWindow->GetOuterWindow())) {
78 0 : mWindowListeners.RemoveElement(weakWindow);
79 0 : continue;
80 : }
81 :
82 0 : nsContentUtils::DispatchTrustedEvent(document, outerWindow,
83 0 : NS_LITERAL_STRING("moztimechange"), /* bubbles = */ true,
84 0 : /* canceable = */ false);
85 : }
86 0 : }
87 :
88 : void
89 0 : nsSystemTimeChangeObserver::Notify(const int64_t& aClockDeltaMS)
90 : {
91 : // Notify observers that the system clock has been adjusted.
92 0 : nsCOMPtr<nsIObserverService> observerService = GetObserverService();
93 0 : if (observerService) {
94 0 : nsString dataStr;
95 0 : dataStr.AppendFloat(static_cast<double>(aClockDeltaMS));
96 0 : observerService->NotifyObservers(
97 0 : nullptr, "system-clock-change", dataStr.get());
98 : }
99 :
100 0 : FireMozTimeChangeEvent();
101 0 : }
102 :
103 : void
104 0 : nsSystemTimeChangeObserver::Notify(
105 : const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
106 : {
107 0 : FireMozTimeChangeEvent();
108 0 : }
109 :
110 : nsresult
111 0 : mozilla::time::AddWindowListener(nsPIDOMWindowInner* aWindow)
112 : {
113 0 : return nsSystemTimeChangeObserver::GetInstance()->AddWindowListenerImpl(aWindow);
114 : }
115 :
116 : nsresult
117 0 : nsSystemTimeChangeObserver::AddWindowListenerImpl(nsPIDOMWindowInner* aWindow)
118 : {
119 0 : if (!aWindow) {
120 0 : return NS_ERROR_ILLEGAL_VALUE;
121 : }
122 :
123 0 : nsWeakPtr windowWeakRef = do_GetWeakReference(aWindow);
124 0 : NS_ASSERTION(windowWeakRef, "nsIDOMWindow implementations shuld support weak ref");
125 :
126 0 : if (mWindowListeners.IndexOf(windowWeakRef) !=
127 : ListenerArray::array_type::NoIndex) {
128 0 : return NS_OK;
129 : }
130 :
131 0 : if (mWindowListeners.IsEmpty()) {
132 0 : RegisterSystemClockChangeObserver(sObserver);
133 0 : RegisterSystemTimezoneChangeObserver(sObserver);
134 : }
135 :
136 0 : mWindowListeners.AppendElement(windowWeakRef);
137 0 : return NS_OK;
138 : }
139 :
140 : nsresult
141 0 : mozilla::time::RemoveWindowListener(nsPIDOMWindowInner* aWindow)
142 : {
143 0 : if (!sObserver) {
144 0 : return NS_OK;
145 : }
146 :
147 0 : return nsSystemTimeChangeObserver::GetInstance()->RemoveWindowListenerImpl(aWindow);
148 : }
149 :
150 : nsresult
151 0 : nsSystemTimeChangeObserver::RemoveWindowListenerImpl(nsPIDOMWindowInner* aWindow)
152 : {
153 0 : if (!aWindow) {
154 0 : return NS_OK;
155 : }
156 :
157 0 : nsWeakPtr windowWeakRef = do_GetWeakReference(aWindow);
158 0 : mWindowListeners.RemoveElement(windowWeakRef);
159 :
160 0 : if (mWindowListeners.IsEmpty()) {
161 0 : UnregisterSystemClockChangeObserver(sObserver);
162 0 : UnregisterSystemTimezoneChangeObserver(sObserver);
163 : }
164 :
165 0 : return NS_OK;
166 : }
|