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/. */
6 
7 #include "ScreenHelperWin.h"
8 
9 #include "mozilla/Logging.h"
10 #include "nsTArray.h"
11 #include "WinUtils.h"
12 
13 static mozilla::LazyLogModule sScreenLog("WidgetScreen");
14 
15 namespace mozilla {
16 namespace widget {
17 
CollectMonitors(HMONITOR aMon,HDC,LPRECT,LPARAM ioParam)18 BOOL CALLBACK CollectMonitors(HMONITOR aMon, HDC, LPRECT, LPARAM ioParam) {
19   auto screens = reinterpret_cast<nsTArray<RefPtr<Screen>>*>(ioParam);
20   BOOL success = FALSE;
21   MONITORINFOEX info;
22   info.cbSize = sizeof(MONITORINFOEX);
23   success = ::GetMonitorInfoW(aMon, &info);
24   if (!success) {
25     MOZ_LOG(sScreenLog, LogLevel::Error, ("GetMonitorInfoW failed"));
26     return TRUE;  // continue the enumeration
27   }
28 
29   double scale = WinUtils::LogToPhysFactor(aMon);
30   DesktopToLayoutDeviceScale contentsScaleFactor;
31   if (WinUtils::IsPerMonitorDPIAware()) {
32     contentsScaleFactor.scale = 1.0;
33   } else {
34     contentsScaleFactor.scale = scale;
35   }
36   CSSToLayoutDeviceScale defaultCssScaleFactor(scale);
37   LayoutDeviceIntRect rect(info.rcMonitor.left, info.rcMonitor.top,
38                            info.rcMonitor.right - info.rcMonitor.left,
39                            info.rcMonitor.bottom - info.rcMonitor.top);
40   LayoutDeviceIntRect availRect(info.rcWork.left, info.rcWork.top,
41                                 info.rcWork.right - info.rcWork.left,
42                                 info.rcWork.bottom - info.rcWork.top);
43 
44   HDC hDC = CreateDC(nullptr, info.szDevice, nullptr, nullptr);
45   if (!hDC) {
46     MOZ_LOG(sScreenLog, LogLevel::Error, ("CollectMonitors CreateDC failed"));
47     return TRUE;
48   }
49   uint32_t pixelDepth = ::GetDeviceCaps(hDC, BITSPIXEL);
50   DeleteDC(hDC);
51   if (pixelDepth == 32) {
52     // If a device uses 32 bits per pixel, it's still only using 8 bits
53     // per color component, which is what our callers want to know.
54     // (Some devices report 32 and some devices report 24.)
55     pixelDepth = 24;
56   }
57 
58   float dpi = WinUtils::MonitorDPI(aMon);
59 
60   hal::ScreenOrientation orientation;
61   uint16_t angle;
62   WinUtils::GetDisplayOrientation(info.szDevice, orientation, angle);
63 
64   MOZ_LOG(sScreenLog, LogLevel::Debug,
65           ("New screen [%s (%s) %d %f %f %f %d %d]", ToString(rect).c_str(),
66            ToString(availRect).c_str(), pixelDepth, contentsScaleFactor.scale,
67            defaultCssScaleFactor.scale, dpi, orientation, angle));
68   auto screen =
69       new Screen(rect, availRect, pixelDepth, pixelDepth, contentsScaleFactor,
70                  defaultCssScaleFactor, dpi, orientation, angle);
71   if (info.dwFlags & MONITORINFOF_PRIMARY) {
72     // The primary monitor must be the first element of the screen list.
73     screens->InsertElementAt(0, std::move(screen));
74   } else {
75     screens->AppendElement(std::move(screen));
76   }
77   return TRUE;
78 }
79 
RefreshScreens()80 void ScreenHelperWin::RefreshScreens() {
81   MOZ_LOG(sScreenLog, LogLevel::Debug, ("Refreshing screens"));
82 
83   AutoTArray<RefPtr<Screen>, 4> screens;
84   BOOL result = ::EnumDisplayMonitors(
85       nullptr, nullptr, (MONITORENUMPROC)CollectMonitors, (LPARAM)&screens);
86   if (!result) {
87     NS_WARNING("Unable to EnumDisplayMonitors");
88   }
89   ScreenManager::Refresh(std::move(screens));
90 }
91 
92 }  // namespace widget
93 }  // namespace mozilla
94