Bug 1073336 part 12 - Add AnimationPlayer::GetCollection(); r=dbaron
[gecko.git] / widget / nsScreenManagerProxy.cpp
blob747e2fbe6170a581eabdcd7f13b449eece7f28a2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
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
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/unused.h"
8 #include "mozilla/dom/ContentChild.h"
9 #include "nsScreenManagerProxy.h"
10 #include "nsServiceManagerUtils.h"
11 #include "nsIAppShell.h"
12 #include "nsIScreen.h"
13 #include "nsIScreenManager.h"
14 #include "nsWidgetsCID.h"
16 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
18 using namespace mozilla;
19 using namespace mozilla::dom;
20 using namespace mozilla::widget;
22 NS_IMPL_ISUPPORTS(nsScreenManagerProxy, nsIScreenManager)
24 nsScreenManagerProxy::nsScreenManagerProxy()
25 : mNumberOfScreens(-1)
26 , mSystemDefaultScale(1.0)
27 , mCacheValid(true)
28 , mCacheWillInvalidate(false)
30 bool success = false;
31 unused << ContentChild::GetSingleton()->SendPScreenManagerConstructor(
32 this,
33 &mNumberOfScreens,
34 &mSystemDefaultScale,
35 &success);
37 if (!success) {
38 // We're in bad shape. We'll return the default values, but we'll basically
39 // be lying.
40 NS_WARNING("Setting up communications with the parent nsIScreenManager failed.");
43 InvalidateCacheOnNextTick();
45 // nsScreenManagerProxy is a service, which will always have a reference
46 // held to it by the Component Manager once the service is requested.
47 // However, nsScreenManagerProxy also implements PScreenManagerChild, and
48 // that means that the manager of the PScreenManager protocol (PContent
49 // in this case) needs to know how to deallocate this actor. We AddRef here
50 // so that in the event that PContent tries to deallocate us either before
51 // or after process shutdown, we don't try to do a double-free.
52 AddRef();
55 /**
56 * nsIScreenManager
57 **/
59 NS_IMETHODIMP
60 nsScreenManagerProxy::GetPrimaryScreen(nsIScreen** outScreen)
62 InvalidateCacheOnNextTick();
64 if (!mPrimaryScreen) {
65 ScreenDetails details;
66 bool success = false;
67 unused << SendGetPrimaryScreen(&details, &success);
68 if (!success) {
69 return NS_ERROR_FAILURE;
72 mPrimaryScreen = new ScreenProxy(this, details);
74 NS_ADDREF(*outScreen = mPrimaryScreen);
75 return NS_OK;
78 NS_IMETHODIMP
79 nsScreenManagerProxy::ScreenForId(uint32_t aId, nsIScreen** outScreen)
81 // At this time, there's no need for child processes to query for
82 // screens by ID.
83 return NS_ERROR_NOT_IMPLEMENTED;
86 NS_IMETHODIMP
87 nsScreenManagerProxy::ScreenForRect(int32_t inLeft,
88 int32_t inTop,
89 int32_t inWidth,
90 int32_t inHeight,
91 nsIScreen** outScreen)
93 bool success = false;
94 ScreenDetails details;
95 unused << SendScreenForRect(inLeft, inTop, inWidth, inHeight, &details, &success);
96 if (!success) {
97 return NS_ERROR_FAILURE;
100 nsRefPtr<ScreenProxy> screen = new ScreenProxy(this, details);
101 NS_ADDREF(*outScreen = screen);
103 return NS_OK;
106 NS_IMETHODIMP
107 nsScreenManagerProxy::ScreenForNativeWidget(void* aWidget,
108 nsIScreen** outScreen)
110 // Because ScreenForNativeWidget can be called numerous times
111 // indirectly from content via the DOM Screen API, we cache the
112 // results for this tick of the event loop.
113 TabChild* tabChild = static_cast<TabChild*>(aWidget);
115 // Enumerate the cached screen array, looking for one that has
116 // the TabChild that we're looking for...
117 for (uint32_t i = 0; i < mScreenCache.Length(); ++i) {
118 ScreenCacheEntry& curr = mScreenCache[i];
119 if (curr.mTabChild == aWidget) {
120 NS_ADDREF(*outScreen = static_cast<nsIScreen*>(curr.mScreenProxy));
121 return NS_OK;
125 // Never cached this screen, so we have to ask the parent process
126 // for it.
127 bool success = false;
128 ScreenDetails details;
129 unused << SendScreenForBrowser(tabChild, &details, &success);
130 if (!success) {
131 return NS_ERROR_FAILURE;
134 ScreenCacheEntry newEntry;
135 nsRefPtr<ScreenProxy> screen = new ScreenProxy(this, details);
137 newEntry.mScreenProxy = screen;
138 newEntry.mTabChild = tabChild;
140 mScreenCache.AppendElement(newEntry);
142 NS_ADDREF(*outScreen = screen);
144 InvalidateCacheOnNextTick();
145 return NS_OK;
148 NS_IMETHODIMP
149 nsScreenManagerProxy::GetNumberOfScreens(uint32_t* aNumberOfScreens)
151 if (!EnsureCacheIsValid()) {
152 return NS_ERROR_FAILURE;
155 *aNumberOfScreens = mNumberOfScreens;
156 return NS_OK;
159 NS_IMETHODIMP
160 nsScreenManagerProxy::GetSystemDefaultScale(float *aSystemDefaultScale)
162 if (!EnsureCacheIsValid()) {
163 return NS_ERROR_FAILURE;
166 *aSystemDefaultScale = mSystemDefaultScale;
167 return NS_OK;
170 bool
171 nsScreenManagerProxy::EnsureCacheIsValid()
173 if (mCacheValid) {
174 return true;
177 bool success = false;
178 // Kick off a synchronous IPC call to the parent to get the
179 // most up-to-date information.
180 unused << SendRefresh(&mNumberOfScreens, &mSystemDefaultScale, &success);
181 if (!success) {
182 NS_WARNING("Refreshing nsScreenManagerProxy failed in the parent process.");
183 return false;
186 mCacheValid = true;
188 InvalidateCacheOnNextTick();
189 return true;
192 void
193 nsScreenManagerProxy::InvalidateCacheOnNextTick()
195 if (mCacheWillInvalidate) {
196 return;
199 mCacheWillInvalidate = true;
201 nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
202 if (appShell) {
203 appShell->RunInStableState(
204 NS_NewRunnableMethod(this, &nsScreenManagerProxy::InvalidateCache)
206 } else {
207 // It's pretty bad news if we can't get the appshell. In that case,
208 // let's just invalidate the cache right away.
209 InvalidateCache();
213 void
214 nsScreenManagerProxy::InvalidateCache()
216 mCacheValid = false;
217 mCacheWillInvalidate = false;
219 if (mPrimaryScreen) {
220 mPrimaryScreen = nullptr;
222 for (int32_t i = mScreenCache.Length() - 1; i >= 0; --i) {
223 mScreenCache.RemoveElementAt(i);