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