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)
28 , mCacheWillInvalidate(false)
31 unused
<< ContentChild::GetSingleton()->SendPScreenManagerConstructor(
38 // We're in bad shape. We'll return the default values, but we'll basically
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.
60 nsScreenManagerProxy::GetPrimaryScreen(nsIScreen
** outScreen
)
62 InvalidateCacheOnNextTick();
64 if (!mPrimaryScreen
) {
65 ScreenDetails details
;
67 unused
<< SendGetPrimaryScreen(&details
, &success
);
69 return NS_ERROR_FAILURE
;
72 mPrimaryScreen
= new ScreenProxy(this, details
);
74 NS_ADDREF(*outScreen
= mPrimaryScreen
);
79 nsScreenManagerProxy::ScreenForId(uint32_t aId
, nsIScreen
** outScreen
)
81 // At this time, there's no need for child processes to query for
83 return NS_ERROR_NOT_IMPLEMENTED
;
87 nsScreenManagerProxy::ScreenForRect(int32_t inLeft
,
91 nsIScreen
** outScreen
)
94 ScreenDetails details
;
95 unused
<< SendScreenForRect(inLeft
, inTop
, inWidth
, inHeight
, &details
, &success
);
97 return NS_ERROR_FAILURE
;
100 nsRefPtr
<ScreenProxy
> screen
= new ScreenProxy(this, details
);
101 NS_ADDREF(*outScreen
= screen
);
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
));
125 // Never cached this screen, so we have to ask the parent process
127 bool success
= false;
128 ScreenDetails details
;
129 unused
<< SendScreenForBrowser(tabChild
, &details
, &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();
149 nsScreenManagerProxy::GetNumberOfScreens(uint32_t* aNumberOfScreens
)
151 if (!EnsureCacheIsValid()) {
152 return NS_ERROR_FAILURE
;
155 *aNumberOfScreens
= mNumberOfScreens
;
160 nsScreenManagerProxy::GetSystemDefaultScale(float *aSystemDefaultScale
)
162 if (!EnsureCacheIsValid()) {
163 return NS_ERROR_FAILURE
;
166 *aSystemDefaultScale
= mSystemDefaultScale
;
171 nsScreenManagerProxy::EnsureCacheIsValid()
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
);
182 NS_WARNING("Refreshing nsScreenManagerProxy failed in the parent process.");
188 InvalidateCacheOnNextTick();
193 nsScreenManagerProxy::InvalidateCacheOnNextTick()
195 if (mCacheWillInvalidate
) {
199 mCacheWillInvalidate
= true;
201 nsCOMPtr
<nsIAppShell
> appShell
= do_GetService(kAppShellCID
);
203 appShell
->RunInStableState(
204 NS_NewRunnableMethod(this, &nsScreenManagerProxy::InvalidateCache
)
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.
214 nsScreenManagerProxy::InvalidateCache()
217 mCacheWillInvalidate
= false;
219 if (mPrimaryScreen
) {
220 mPrimaryScreen
= nullptr;
222 for (int32_t i
= mScreenCache
.Length() - 1; i
>= 0; --i
) {
223 mScreenCache
.RemoveElementAt(i
);