Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / widget / windows / ScreenHelperWin.cpp
blob945b8d1895a0c95cb1bb8f75df3e5bfbca59da5d
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 "ScreenHelperWin.h"
9 #include "mozilla/Logging.h"
10 #include "mozilla/gfx/DeviceManagerDx.h"
11 #include "nsTArray.h"
12 #include "WinUtils.h"
14 #include <dxgi.h>
16 static mozilla::LazyLogModule sScreenLog("WidgetScreen");
18 namespace mozilla {
19 namespace widget {
21 static void GetDisplayInfo(const char16ptr_t aName,
22 hal::ScreenOrientation& aOrientation,
23 uint16_t& aAngle, bool& aIsPseudoDisplay,
24 uint32_t& aRefreshRate) {
25 DISPLAY_DEVICEW displayDevice = {.cb = sizeof(DISPLAY_DEVICEW)};
27 // XXX Is the pseudodisplay status really useful?
28 aIsPseudoDisplay =
29 EnumDisplayDevicesW(aName, 0, &displayDevice, 0) &&
30 (displayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER);
32 DEVMODEW mode = {.dmSize = sizeof(DEVMODEW)};
33 if (!EnumDisplaySettingsW(aName, ENUM_CURRENT_SETTINGS, &mode)) {
34 return;
36 MOZ_ASSERT(mode.dmFields & DM_DISPLAYORIENTATION);
38 aRefreshRate = mode.dmDisplayFrequency;
40 // conver to default/natural size
41 if (mode.dmDisplayOrientation == DMDO_90 ||
42 mode.dmDisplayOrientation == DMDO_270) {
43 DWORD temp = mode.dmPelsHeight;
44 mode.dmPelsHeight = mode.dmPelsWidth;
45 mode.dmPelsWidth = temp;
48 bool defaultIsLandscape = mode.dmPelsWidth >= mode.dmPelsHeight;
49 switch (mode.dmDisplayOrientation) {
50 case DMDO_DEFAULT:
51 aOrientation = defaultIsLandscape
52 ? hal::ScreenOrientation::LandscapePrimary
53 : hal::ScreenOrientation::PortraitPrimary;
54 aAngle = 0;
55 break;
56 case DMDO_90:
57 aOrientation = defaultIsLandscape
58 ? hal::ScreenOrientation::PortraitPrimary
59 : hal::ScreenOrientation::LandscapeSecondary;
60 aAngle = 270;
61 break;
62 case DMDO_180:
63 aOrientation = defaultIsLandscape
64 ? hal::ScreenOrientation::LandscapeSecondary
65 : hal::ScreenOrientation::PortraitSecondary;
66 aAngle = 180;
67 break;
68 case DMDO_270:
69 aOrientation = defaultIsLandscape
70 ? hal::ScreenOrientation::PortraitSecondary
71 : hal::ScreenOrientation::LandscapePrimary;
72 aAngle = 90;
73 break;
74 default:
75 MOZ_ASSERT_UNREACHABLE("Unexpected angle");
76 break;
80 struct CollectMonitorsParam {
81 nsTArray<RefPtr<Screen>> screens;
84 BOOL CALLBACK CollectMonitors(HMONITOR aMon, HDC, LPRECT, LPARAM ioParam) {
85 CollectMonitorsParam* cmParam =
86 reinterpret_cast<CollectMonitorsParam*>(ioParam);
87 BOOL success = FALSE;
88 MONITORINFOEX info;
89 info.cbSize = sizeof(MONITORINFOEX);
90 success = ::GetMonitorInfoW(aMon, &info);
91 if (!success) {
92 MOZ_LOG(sScreenLog, LogLevel::Error, ("GetMonitorInfoW failed"));
93 return TRUE; // continue the enumeration
96 double scale = WinUtils::LogToPhysFactor(aMon);
97 DesktopToLayoutDeviceScale contentsScaleFactor;
98 if (WinUtils::IsPerMonitorDPIAware()) {
99 contentsScaleFactor.scale = 1.0;
100 } else {
101 contentsScaleFactor.scale = scale;
103 CSSToLayoutDeviceScale defaultCssScaleFactor(scale);
104 LayoutDeviceIntRect rect(info.rcMonitor.left, info.rcMonitor.top,
105 info.rcMonitor.right - info.rcMonitor.left,
106 info.rcMonitor.bottom - info.rcMonitor.top);
107 LayoutDeviceIntRect availRect(info.rcWork.left, info.rcWork.top,
108 info.rcWork.right - info.rcWork.left,
109 info.rcWork.bottom - info.rcWork.top);
111 HDC hDC = CreateDC(nullptr, info.szDevice, nullptr, nullptr);
112 if (!hDC) {
113 MOZ_LOG(sScreenLog, LogLevel::Error, ("CollectMonitors CreateDC failed"));
114 return TRUE;
116 uint32_t pixelDepth = ::GetDeviceCaps(hDC, BITSPIXEL);
117 DeleteDC(hDC);
118 if (pixelDepth == 32) {
119 // If a device uses 32 bits per pixel, it's still only using 8 bits
120 // per color component, which is what our callers want to know.
121 // (Some devices report 32 and some devices report 24.)
122 pixelDepth = 24;
125 float dpi = WinUtils::MonitorDPI(aMon);
127 auto orientation = hal::ScreenOrientation::None;
128 uint16_t angle = 0;
129 bool isPseudoDisplay = false;
130 uint32_t refreshRate = 0;
131 GetDisplayInfo(info.szDevice, orientation, angle, isPseudoDisplay,
132 refreshRate);
134 auto* manager = gfx::DeviceManagerDx::Get();
135 bool isHDR = manager ? manager->MonitorHDREnabled(aMon) : false;
137 MOZ_LOG(sScreenLog, LogLevel::Debug,
138 ("New screen [%s (%s) %d %u %f %f %f %d %d %d]",
139 ToString(rect).c_str(), ToString(availRect).c_str(), pixelDepth,
140 refreshRate, contentsScaleFactor.scale, defaultCssScaleFactor.scale,
141 dpi, isPseudoDisplay, uint32_t(orientation), angle));
142 auto screen = MakeRefPtr<Screen>(
143 rect, availRect, pixelDepth, pixelDepth, refreshRate, contentsScaleFactor,
144 defaultCssScaleFactor, dpi, Screen::IsPseudoDisplay(isPseudoDisplay),
145 Screen::IsHDR(isHDR), orientation, angle);
146 if (info.dwFlags & MONITORINFOF_PRIMARY) {
147 // The primary monitor must be the first element of the screen list.
148 cmParam->screens.InsertElementAt(0, std::move(screen));
149 } else {
150 cmParam->screens.AppendElement(std::move(screen));
152 return TRUE;
155 /* static */
156 void ScreenHelperWin::RefreshScreens() {
157 MOZ_LOG(sScreenLog, LogLevel::Debug, ("Refreshing screens"));
159 auto* manager = gfx::DeviceManagerDx::Get();
160 if (XRE_IsParentProcess() && manager) {
161 manager->UpdateMonitorInfo();
164 CollectMonitorsParam cmParam;
165 BOOL result = ::EnumDisplayMonitors(
166 nullptr, nullptr, (MONITORENUMPROC)CollectMonitors, (LPARAM)&cmParam);
167 if (!result) {
168 NS_WARNING("Unable to EnumDisplayMonitors");
170 ScreenManager::Refresh(std::move(cmParam.screens));
173 } // namespace widget
174 } // namespace mozilla