nsScreenManagerProxy.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  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/. */
  6. #include "mozilla/Unused.h"
  7. #include "mozilla/dom/ContentChild.h"
  8. #include "nsScreenManagerProxy.h"
  9. #include "nsServiceManagerUtils.h"
  10. #include "nsContentUtils.h"
  11. #include "nsIAppShell.h"
  12. #include "nsIScreen.h"
  13. #include "nsIScreenManager.h"
  14. #include "nsWidgetsCID.h"
  15. static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
  16. using namespace mozilla;
  17. using namespace mozilla::dom;
  18. using namespace mozilla::widget;
  19. NS_IMPL_ISUPPORTS(nsScreenManagerProxy, nsIScreenManager)
  20. nsScreenManagerProxy::nsScreenManagerProxy()
  21. : mNumberOfScreens(-1)
  22. , mSystemDefaultScale(1.0)
  23. , mCacheValid(true)
  24. , mCacheWillInvalidate(false)
  25. {
  26. bool success = false;
  27. Unused << ContentChild::GetSingleton()->SendPScreenManagerConstructor(
  28. this,
  29. &mNumberOfScreens,
  30. &mSystemDefaultScale,
  31. &success);
  32. if (!success) {
  33. // We're in bad shape. We'll return the default values, but we'll basically
  34. // be lying.
  35. NS_WARNING("Setting up communications with the parent nsIScreenManager failed.");
  36. }
  37. InvalidateCacheOnNextTick();
  38. // nsScreenManagerProxy is a service, which will always have a reference
  39. // held to it by the Component Manager once the service is requested.
  40. // However, nsScreenManagerProxy also implements PScreenManagerChild, and
  41. // that means that the manager of the PScreenManager protocol (PContent
  42. // in this case) needs to know how to deallocate this actor. We AddRef here
  43. // so that in the event that PContent tries to deallocate us either before
  44. // or after process shutdown, we don't try to do a double-free.
  45. AddRef();
  46. }
  47. /**
  48. * nsIScreenManager
  49. **/
  50. NS_IMETHODIMP
  51. nsScreenManagerProxy::GetPrimaryScreen(nsIScreen** outScreen)
  52. {
  53. InvalidateCacheOnNextTick();
  54. if (!mPrimaryScreen) {
  55. ScreenDetails details;
  56. bool success = false;
  57. Unused << SendGetPrimaryScreen(&details, &success);
  58. if (!success) {
  59. return NS_ERROR_FAILURE;
  60. }
  61. mPrimaryScreen = new ScreenProxy(this, details);
  62. }
  63. NS_ADDREF(*outScreen = mPrimaryScreen);
  64. return NS_OK;
  65. }
  66. NS_IMETHODIMP
  67. nsScreenManagerProxy::ScreenForId(uint32_t aId, nsIScreen** outScreen)
  68. {
  69. // At this time, there's no need for child processes to query for
  70. // screens by ID.
  71. return NS_ERROR_NOT_IMPLEMENTED;
  72. }
  73. NS_IMETHODIMP
  74. nsScreenManagerProxy::ScreenForRect(int32_t inLeft,
  75. int32_t inTop,
  76. int32_t inWidth,
  77. int32_t inHeight,
  78. nsIScreen** outScreen)
  79. {
  80. bool success = false;
  81. ScreenDetails details;
  82. Unused << SendScreenForRect(inLeft, inTop, inWidth, inHeight, &details, &success);
  83. if (!success) {
  84. return NS_ERROR_FAILURE;
  85. }
  86. RefPtr<ScreenProxy> screen = new ScreenProxy(this, details);
  87. NS_ADDREF(*outScreen = screen);
  88. return NS_OK;
  89. }
  90. NS_IMETHODIMP
  91. nsScreenManagerProxy::ScreenForNativeWidget(void* aWidget,
  92. nsIScreen** outScreen)
  93. {
  94. // Because ScreenForNativeWidget can be called numerous times
  95. // indirectly from content via the DOM Screen API, we cache the
  96. // results for this tick of the event loop.
  97. TabChild* tabChild = static_cast<TabChild*>(aWidget);
  98. // Enumerate the cached screen array, looking for one that has
  99. // the TabChild that we're looking for...
  100. for (uint32_t i = 0; i < mScreenCache.Length(); ++i) {
  101. ScreenCacheEntry& curr = mScreenCache[i];
  102. if (curr.mTabChild == aWidget) {
  103. NS_ADDREF(*outScreen = static_cast<nsIScreen*>(curr.mScreenProxy));
  104. return NS_OK;
  105. }
  106. }
  107. // Never cached this screen, so we have to ask the parent process
  108. // for it.
  109. bool success = false;
  110. ScreenDetails details;
  111. Unused << SendScreenForBrowser(tabChild->GetTabId(), &details, &success);
  112. if (!success) {
  113. return NS_ERROR_FAILURE;
  114. }
  115. ScreenCacheEntry newEntry;
  116. RefPtr<ScreenProxy> screen = new ScreenProxy(this, details);
  117. newEntry.mScreenProxy = screen;
  118. newEntry.mTabChild = tabChild;
  119. mScreenCache.AppendElement(newEntry);
  120. NS_ADDREF(*outScreen = screen);
  121. InvalidateCacheOnNextTick();
  122. return NS_OK;
  123. }
  124. NS_IMETHODIMP
  125. nsScreenManagerProxy::GetNumberOfScreens(uint32_t* aNumberOfScreens)
  126. {
  127. if (!EnsureCacheIsValid()) {
  128. return NS_ERROR_FAILURE;
  129. }
  130. *aNumberOfScreens = mNumberOfScreens;
  131. return NS_OK;
  132. }
  133. NS_IMETHODIMP
  134. nsScreenManagerProxy::GetSystemDefaultScale(float *aSystemDefaultScale)
  135. {
  136. if (!EnsureCacheIsValid()) {
  137. return NS_ERROR_FAILURE;
  138. }
  139. *aSystemDefaultScale = mSystemDefaultScale;
  140. return NS_OK;
  141. }
  142. bool
  143. nsScreenManagerProxy::EnsureCacheIsValid()
  144. {
  145. if (mCacheValid) {
  146. return true;
  147. }
  148. bool success = false;
  149. // Kick off a synchronous IPC call to the parent to get the
  150. // most up-to-date information.
  151. Unused << SendRefresh(&mNumberOfScreens, &mSystemDefaultScale, &success);
  152. if (!success) {
  153. NS_WARNING("Refreshing nsScreenManagerProxy failed in the parent process.");
  154. return false;
  155. }
  156. mCacheValid = true;
  157. InvalidateCacheOnNextTick();
  158. return true;
  159. }
  160. void
  161. nsScreenManagerProxy::InvalidateCacheOnNextTick()
  162. {
  163. if (mCacheWillInvalidate) {
  164. return;
  165. }
  166. mCacheWillInvalidate = true;
  167. nsContentUtils::RunInStableState(NewRunnableMethod(this, &nsScreenManagerProxy::InvalidateCache));
  168. }
  169. void
  170. nsScreenManagerProxy::InvalidateCache()
  171. {
  172. mCacheValid = false;
  173. mCacheWillInvalidate = false;
  174. if (mPrimaryScreen) {
  175. mPrimaryScreen = nullptr;
  176. }
  177. for (int32_t i = mScreenCache.Length() - 1; i >= 0; --i) {
  178. mScreenCache.RemoveElementAt(i);
  179. }
  180. }