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"
13 static mozilla::LazyLogModule
sScreenLog("WidgetScreen");
18 static void GetDisplayInfo(const char16ptr_t aName
,
19 hal::ScreenOrientation
& aOrientation
,
20 uint16_t& aAngle
, bool& aIsPseudoDisplay
,
21 uint32_t& aRefreshRate
) {
22 DISPLAY_DEVICEW displayDevice
= {.cb
= sizeof(DISPLAY_DEVICEW
)};
24 // XXX Is the pseudodisplay status really useful?
26 EnumDisplayDevicesW(aName
, 0, &displayDevice
, 0) &&
27 (displayDevice
.StateFlags
& DISPLAY_DEVICE_MIRRORING_DRIVER
);
29 DEVMODEW mode
= {.dmSize
= sizeof(DEVMODEW
)};
30 if (!EnumDisplaySettingsW(aName
, ENUM_CURRENT_SETTINGS
, &mode
)) {
33 MOZ_ASSERT(mode
.dmFields
& DM_DISPLAYORIENTATION
);
35 aRefreshRate
= mode
.dmDisplayFrequency
;
37 // conver to default/natural size
38 if (mode
.dmDisplayOrientation
== DMDO_90
||
39 mode
.dmDisplayOrientation
== DMDO_270
) {
40 DWORD temp
= mode
.dmPelsHeight
;
41 mode
.dmPelsHeight
= mode
.dmPelsWidth
;
42 mode
.dmPelsWidth
= temp
;
45 bool defaultIsLandscape
= mode
.dmPelsWidth
>= mode
.dmPelsHeight
;
46 switch (mode
.dmDisplayOrientation
) {
48 aOrientation
= defaultIsLandscape
49 ? hal::ScreenOrientation::LandscapePrimary
50 : hal::ScreenOrientation::PortraitPrimary
;
54 aOrientation
= defaultIsLandscape
55 ? hal::ScreenOrientation::PortraitPrimary
56 : hal::ScreenOrientation::LandscapeSecondary
;
60 aOrientation
= defaultIsLandscape
61 ? hal::ScreenOrientation::LandscapeSecondary
62 : hal::ScreenOrientation::PortraitSecondary
;
66 aOrientation
= defaultIsLandscape
67 ? hal::ScreenOrientation::PortraitSecondary
68 : hal::ScreenOrientation::LandscapePrimary
;
72 MOZ_ASSERT_UNREACHABLE("Unexpected angle");
77 BOOL CALLBACK
CollectMonitors(HMONITOR aMon
, HDC
, LPRECT
, LPARAM ioParam
) {
78 auto screens
= reinterpret_cast<nsTArray
<RefPtr
<Screen
>>*>(ioParam
);
81 info
.cbSize
= sizeof(MONITORINFOEX
);
82 success
= ::GetMonitorInfoW(aMon
, &info
);
84 MOZ_LOG(sScreenLog
, LogLevel::Error
, ("GetMonitorInfoW failed"));
85 return TRUE
; // continue the enumeration
88 double scale
= WinUtils::LogToPhysFactor(aMon
);
89 DesktopToLayoutDeviceScale contentsScaleFactor
;
90 if (WinUtils::IsPerMonitorDPIAware()) {
91 contentsScaleFactor
.scale
= 1.0;
93 contentsScaleFactor
.scale
= scale
;
95 CSSToLayoutDeviceScale
defaultCssScaleFactor(scale
);
96 LayoutDeviceIntRect
rect(info
.rcMonitor
.left
, info
.rcMonitor
.top
,
97 info
.rcMonitor
.right
- info
.rcMonitor
.left
,
98 info
.rcMonitor
.bottom
- info
.rcMonitor
.top
);
99 LayoutDeviceIntRect
availRect(info
.rcWork
.left
, info
.rcWork
.top
,
100 info
.rcWork
.right
- info
.rcWork
.left
,
101 info
.rcWork
.bottom
- info
.rcWork
.top
);
103 HDC hDC
= CreateDC(nullptr, info
.szDevice
, nullptr, nullptr);
105 MOZ_LOG(sScreenLog
, LogLevel::Error
, ("CollectMonitors CreateDC failed"));
108 uint32_t pixelDepth
= ::GetDeviceCaps(hDC
, BITSPIXEL
);
110 if (pixelDepth
== 32) {
111 // If a device uses 32 bits per pixel, it's still only using 8 bits
112 // per color component, which is what our callers want to know.
113 // (Some devices report 32 and some devices report 24.)
117 float dpi
= WinUtils::MonitorDPI(aMon
);
119 auto orientation
= hal::ScreenOrientation::None
;
121 bool isPseudoDisplay
= false;
122 uint32_t refreshRate
= 0;
123 GetDisplayInfo(info
.szDevice
, orientation
, angle
, isPseudoDisplay
,
126 MOZ_LOG(sScreenLog
, LogLevel::Debug
,
127 ("New screen [%s (%s) %d %u %f %f %f %d %d %d]",
128 ToString(rect
).c_str(), ToString(availRect
).c_str(), pixelDepth
,
129 refreshRate
, contentsScaleFactor
.scale
, defaultCssScaleFactor
.scale
,
130 dpi
, isPseudoDisplay
, uint32_t(orientation
), angle
));
131 auto screen
= MakeRefPtr
<Screen
>(
132 rect
, availRect
, pixelDepth
, pixelDepth
, refreshRate
, contentsScaleFactor
,
133 defaultCssScaleFactor
, dpi
, Screen::IsPseudoDisplay(isPseudoDisplay
),
135 if (info
.dwFlags
& MONITORINFOF_PRIMARY
) {
136 // The primary monitor must be the first element of the screen list.
137 screens
->InsertElementAt(0, std::move(screen
));
139 screens
->AppendElement(std::move(screen
));
144 void ScreenHelperWin::RefreshScreens() {
145 MOZ_LOG(sScreenLog
, LogLevel::Debug
, ("Refreshing screens"));
147 AutoTArray
<RefPtr
<Screen
>, 4> screens
;
148 BOOL result
= ::EnumDisplayMonitors(
149 nullptr, nullptr, (MONITORENUMPROC
)CollectMonitors
, (LPARAM
)&screens
);
151 NS_WARNING("Unable to EnumDisplayMonitors");
153 ScreenManager::Refresh(std::move(screens
));
156 } // namespace widget
157 } // namespace mozilla