Bug 1194751 - Part 4. Add ScreenManager and Screen classes. r?mconley,jimm,karlt
ScreenManager takes the common parts of ScreenManagerWin,
ScreenManagerGtk and ScreenManagerCocoa. It caches all screen
information in the new Screen class. The cache are updated when the OS
notifies there is a monitor config change; all changes will be pushed to
content processes via PContent (patch part 6.)
Screen is a pure data object. All platform dependent logic will be in
widget specific helper classes.
Each process will have a singleton ScreenManager object. Widget
specific helper object is held alive by the ScreenManager when
necessary, for example to receive updates from the OS.
The change to to VsyncDispatcher.cpp is due to unified-build bustage.
ScreenManager::ScreenForNativeWidget is not implemented because it
will be removed in patch part 6.
MozReview-Commit-ID: 5ezytAXSqHp
***
fixup
MozReview-Commit-ID: DQtq3UVZytA
new file mode 100644
--- /dev/null
+++ b/widget/Screen.cpp
@@ -0,0 +1,133 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Screen.h"
+
+namespace mozilla {
+namespace widget {
+
+NS_IMPL_ISUPPORTS(Screen, nsIScreen)
+
+static uint32_t sScreenId = 0;
+
+Screen::Screen(LayoutDeviceIntRect aRect, LayoutDeviceIntRect aAvailRect,
+ uint32_t aPixelDepth, uint32_t aColorDepth,
+ DesktopToLayoutDeviceScale aContentsScale,
+ CSSToLayoutDeviceScale aDefaultCssScale)
+ : mRect(aRect)
+ , mAvailRect(aAvailRect)
+ , mRectDisplayPix(RoundedToInt(aRect / aContentsScale))
+ , mAvailRectDisplayPix(RoundedToInt(aAvailRect / aContentsScale))
+ , mPixelDepth(aPixelDepth)
+ , mColorDepth(aColorDepth)
+ , mContentsScale(aContentsScale)
+ , mDefaultCssScale(aDefaultCssScale)
+ , mId(++sScreenId)
+{
+}
+
+Screen::Screen(const Screen& aOther)
+ : mRect(aOther.mRect)
+ , mAvailRect(aOther.mAvailRect)
+ , mRectDisplayPix(aOther.mRectDisplayPix)
+ , mAvailRectDisplayPix(aOther.mAvailRectDisplayPix)
+ , mPixelDepth(aOther.mPixelDepth)
+ , mColorDepth(aOther.mColorDepth)
+ , mContentsScale(aOther.mContentsScale)
+ , mDefaultCssScale(aOther.mDefaultCssScale)
+ , mId(aOther.mId)
+{
+}
+
+NS_IMETHODIMP
+Screen::GetId(uint32_t* aOutId)
+{
+ *aOutId = mId;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+Screen::GetRect(int32_t* aOutLeft,
+ int32_t* aOutTop,
+ int32_t* aOutWidth,
+ int32_t* aOutHeight)
+{
+ *aOutLeft = mRect.x;
+ *aOutTop = mRect.y;
+ *aOutWidth = mRect.width;
+ *aOutHeight = mRect.height;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+Screen::GetRectDisplayPix(int32_t* aOutLeft,
+ int32_t* aOutTop,
+ int32_t* aOutWidth,
+ int32_t* aOutHeight)
+{
+ *aOutLeft = mRectDisplayPix.x;
+ *aOutTop = mRectDisplayPix.y;
+ *aOutWidth = mRectDisplayPix.width;
+ *aOutHeight = mRectDisplayPix.height;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+Screen::GetAvailRect(int32_t* aOutLeft,
+ int32_t* aOutTop,
+ int32_t* aOutWidth,
+ int32_t* aOutHeight)
+{
+ *aOutLeft = mAvailRect.x;
+ *aOutTop = mAvailRect.y;
+ *aOutWidth = mAvailRect.width;
+ *aOutHeight = mAvailRect.height;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+Screen::GetAvailRectDisplayPix(int32_t* aOutLeft,
+ int32_t* aOutTop,
+ int32_t* aOutWidth,
+ int32_t* aOutHeight)
+{
+ *aOutLeft = mAvailRectDisplayPix.x;
+ *aOutTop = mAvailRectDisplayPix.y;
+ *aOutWidth = mAvailRectDisplayPix.width;
+ *aOutHeight = mAvailRectDisplayPix.height;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+Screen::GetPixelDepth(int32_t* aPixelDepth)
+{
+ *aPixelDepth = mPixelDepth;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+Screen::GetColorDepth(int32_t* aColorDepth)
+{
+ *aColorDepth = mColorDepth;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+Screen::GetContentsScaleFactor(double *aOutScale)
+{
+ *aOutScale = mContentsScale.scale;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+Screen::GetDefaultCSSScaleFactor(double *aOutScale)
+{
+ *aOutScale = mDefaultCssScale.scale;
+ return NS_OK;
+}
+
+} // namespace widget
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/Screen.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_widget_Screen_h
+#define mozilla_widget_Screen_h
+
+#include "nsIScreen.h"
+
+#include "Units.h"
+
+namespace mozilla {
+namespace widget {
+
+class Screen final : public nsIScreen
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISCREEN
+
+ Screen(LayoutDeviceIntRect aRect, LayoutDeviceIntRect aAvailRect,
+ uint32_t aPixelDepth, uint32_t aColorDepth,
+ DesktopToLayoutDeviceScale aContentsScale,
+ CSSToLayoutDeviceScale aDefaultCssScale);
+ Screen(const Screen& aOther);
+
+private:
+ virtual ~Screen() {}
+
+ LayoutDeviceIntRect mRect;
+ LayoutDeviceIntRect mAvailRect;
+ DesktopIntRect mRectDisplayPix;
+ DesktopIntRect mAvailRectDisplayPix;
+ uint32_t mPixelDepth;
+ uint32_t mColorDepth;
+ DesktopToLayoutDeviceScale mContentsScale;
+ CSSToLayoutDeviceScale mDefaultCssScale;
+ uint32_t mId;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/widget/ScreenManager.cpp
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ScreenManager.h"
+
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/Logging.h"
+#include "mozilla/StaticPtr.h"
+
+static LazyLogModule sScreenLog("WidgetScreen");
+
+NS_IMPL_ISUPPORTS(ScreenManager, nsIScreenManager)
+
+namespace mozilla {
+namespace widget {
+
+ScreenManager::ScreenManager()
+{
+}
+
+ScreenManager::~ScreenManager()
+{
+}
+
+static StaticRefPtr<ScreenManager> sSingleton;
+
+ScreenManager&
+ScreenManager::GetSingleton()
+{
+ if (!sSingleton) {
+ sSingleton = new ScreenManager();
+ ClearOnShutdown(&sSingleton);
+ }
+ return *sSingleton;
+}
+
+already_AddRefed<ScreenManager>
+ScreenManager::GetAddRefedSingleton()
+{
+ RefPtr<ScreenManager> sm = &GetSingleton();
+ return sm.forget();
+}
+
+void
+ScreenManager::SetHelper(UniquePtr<Helper> aHelper)
+{
+ mHelper = Move(aHelper);
+}
+
+void
+ScreenManager::Refresh(nsTArray<RefPtr<Screen>>&& aScreens)
+{
+ mScreenList = Move(aScreens);
+}
+
+NS_IMETHODIMP
+ScreenManager::ScreenForId(uint32_t aId, nsIScreen** aOutScreen)
+{
+ *aOutScreen = nullptr;
+
+ nsresult rv;
+ for (auto& screen : mScreenList) {
+ uint32_t id;
+ rv = screen->GetId(&id);
+ if (NS_SUCCEEDED(rv) && id == aId) {
+ RefPtr<Screen> ret = screen;
+ ret.forget(aOutScreen);
+ return NS_OK;
+ }
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
+// Returns the screen that contains the rectangle. If the rect overlaps
+// multiple screens, it picks the screen with the greatest area of intersection.
+//
+// The coordinates are in desktop pixels.
+//
+NS_IMETHODIMP
+ScreenManager::ScreenForRect(int32_t aX, int32_t aY,
+ int32_t aWidth, int32_t aHeight,
+ nsIScreen** aOutScreen)
+{
+ if (mScreenList.IsEmpty()) {
+ MOZ_LOG(sScreenLog, LogLevel::Warning,
+ ("No screen available. This can happen in xpcshell."));
+ RefPtr<Screen> ret = new Screen(LayoutDeviceIntRect(), LayoutDeviceIntRect(),
+ 0, 0,
+ DesktopToLayoutDeviceScale(),
+ CSSToLayoutDeviceScale());
+ ret.forget(aOutScreen);
+ return NS_OK;
+ }
+
+ // Optimize for the common case. If the number of screens is only
+ // one then just return the primary screen.
+ if (mScreenList.Length() == 1) {
+ return GetPrimaryScreen(aOutScreen);
+ }
+
+ // which screen should we return?
+ Screen* which = mScreenList[0].get();
+
+ // walk the list of screens and find the one that has the most
+ // surface area.
+ uint32_t area = 0;
+ DesktopIntRect windowRect(aX, aY, aWidth, aHeight);
+ for (auto& screen : mScreenList) {
+ int32_t x, y, width, height;
+ x = y = width = height = 0;
+ screen->GetRectDisplayPix(&x, &y, &width, &height);
+ // calculate the surface area
+ DesktopIntRect screenRect(x, y, width, height);
+ screenRect.IntersectRect(screenRect, windowRect);
+ uint32_t tempArea = screenRect.width * screenRect.height;
+ if (tempArea >= area) {
+ which = screen.get();
+ area = tempArea;
+ }
+ }
+
+ RefPtr<Screen> ret = which;
+ ret.forget(aOutScreen);
+ return NS_OK;
+}
+
+// The screen with the menubar/taskbar. This shouldn't be needed very
+// often.
+//
+NS_IMETHODIMP
+ScreenManager::GetPrimaryScreen(nsIScreen** aPrimaryScreen)
+{
+ if (mScreenList.IsEmpty()) {
+ MOZ_LOG(sScreenLog, LogLevel::Warning,
+ ("No screen available. This can happen in xpcshell."));
+ RefPtr<Screen> ret = new Screen(LayoutDeviceIntRect(), LayoutDeviceIntRect(),
+ 0, 0,
+ DesktopToLayoutDeviceScale(),
+ CSSToLayoutDeviceScale());
+ ret.forget(aPrimaryScreen);
+ return NS_OK;
+ }
+
+ RefPtr<Screen> ret = mScreenList[0];
+ ret.forget(aPrimaryScreen);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ScreenManager::GetSystemDefaultScale(float* aDefaultScale)
+{
+ if (mHelper) {
+ *aDefaultScale = mHelper->GetSystemDefaultScale();
+ return NS_OK;
+ }
+ *aDefaultScale = 1;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ScreenManager::ScreenForNativeWidget(void* aWidget, nsIScreen** aOutScreen)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+} // namespace widget
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/ScreenManager.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_widget_ScreenManager_h
+#define mozilla_widget_ScreenManager_h
+
+#include "nsIScreenManager.h"
+
+#include "mozilla/RefPtr.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/widget/Screen.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace widget {
+
+class ScreenManager final : public nsIScreenManager
+{
+public:
+ class Helper
+ {
+ public:
+ virtual float GetSystemDefaultScale() = 0;
+ virtual ~Helper() {};
+ };
+
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISCREENMANAGER
+
+ static ScreenManager& GetSingleton();
+ static already_AddRefed<ScreenManager> GetAddRefedSingleton();
+
+ void SetHelper(UniquePtr<Helper> aHelper);
+ void Refresh(nsTArray<RefPtr<Screen>>&& aScreens);
+
+private:
+ ScreenManager();
+ virtual ~ScreenManager();
+
+ AutoTArray<RefPtr<Screen>, 4> mScreenList;
+ UniquePtr<Helper> mHelper;
+};
+
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // mozilla_widget_ScreenManager_h
--- a/widget/VsyncDispatcher.cpp
+++ b/widget/VsyncDispatcher.cpp
@@ -11,16 +11,18 @@
#include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/layers/CompositorThread.h"
#ifdef MOZ_GECKO_PROFILER
#include "GeckoProfiler.h"
#include "ProfilerMarkers.h"
#endif
+using namespace mozilla::layers;
+
namespace mozilla {
CompositorVsyncDispatcher::CompositorVsyncDispatcher()
: mCompositorObserverLock("CompositorObserverLock")
, mDidShutdown(false)
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(NS_IsMainThread());
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -125,16 +125,18 @@ EXPORTS.mozilla += [
]
EXPORTS.mozilla.widget += [
'CompositorWidget.h',
'IMEData.h',
'InProcessCompositorWidget.h',
'nsAutoRollup.h',
'PuppetBidiKeyboard.h',
+ 'Screen.h',
+ 'ScreenManager.h',
'WidgetMessageUtils.h',
'WindowSurface.h'
]
UNIFIED_SOURCES += [
'CompositorWidget.cpp',
'ContentCache.cpp',
'GfxDriverInfo.cpp',
@@ -157,16 +159,18 @@ UNIFIED_SOURCES += [
'nsIWidgetListener.cpp',
'nsPrimitiveHelpers.cpp',
'nsPrintSettingsImpl.cpp',
'nsScreenManagerProxy.cpp',
'nsTransferable.cpp',
'nsXPLookAndFeel.cpp',
'PuppetBidiKeyboard.cpp',
'PuppetWidget.cpp',
+ 'Screen.cpp',
+ 'ScreenManager.cpp',
'ScreenProxy.cpp',
'SharedWidgetUtils.cpp',
'TextEventDispatcher.cpp',
'VsyncDispatcher.cpp',
'WidgetEventImpl.cpp',
'WidgetUtils.cpp',
]