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"
16 static mozilla::LazyLogModule
sScreenLog("WidgetScreen");
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?
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
)) {
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
) {
51 aOrientation
= defaultIsLandscape
52 ? hal::ScreenOrientation::LandscapePrimary
53 : hal::ScreenOrientation::PortraitPrimary
;
57 aOrientation
= defaultIsLandscape
58 ? hal::ScreenOrientation::PortraitPrimary
59 : hal::ScreenOrientation::LandscapeSecondary
;
63 aOrientation
= defaultIsLandscape
64 ? hal::ScreenOrientation::LandscapeSecondary
65 : hal::ScreenOrientation::PortraitSecondary
;
69 aOrientation
= defaultIsLandscape
70 ? hal::ScreenOrientation::PortraitSecondary
71 : hal::ScreenOrientation::LandscapePrimary
;
75 MOZ_ASSERT_UNREACHABLE("Unexpected angle");
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
);
89 info
.cbSize
= sizeof(MONITORINFOEX
);
90 success
= ::GetMonitorInfoW(aMon
, &info
);
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;
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);
113 MOZ_LOG(sScreenLog
, LogLevel::Error
, ("CollectMonitors CreateDC failed"));
116 uint32_t pixelDepth
= ::GetDeviceCaps(hDC
, BITSPIXEL
);
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.)
125 float dpi
= WinUtils::MonitorDPI(aMon
);
127 auto orientation
= hal::ScreenOrientation::None
;
129 bool isPseudoDisplay
= false;
130 uint32_t refreshRate
= 0;
131 GetDisplayInfo(info
.szDevice
, orientation
, angle
, isPseudoDisplay
,
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
));
150 cmParam
->screens
.AppendElement(std::move(screen
));
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
);
168 NS_WARNING("Unable to EnumDisplayMonitors");
170 ScreenManager::Refresh(std::move(cmParam
.screens
));
173 } // namespace widget
174 } // namespace mozilla