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   MOZ_LOG(sScreenLog, LogLevel::Debug,
60           ("New screen [%d %d %d %d (%d %d %d %d) %d %f %f %f]", rect.X(),
61            rect.Y(), rect.Width(), rect.Height(), availRect.X(), availRect.Y(),
62            availRect.Width(), availRect.Height(), pixelDepth,
63            contentsScaleFactor.scale, defaultCssScaleFactor.scale, dpi));
64   auto screen = new Screen(rect, availRect, pixelDepth, pixelDepth,
65                            contentsScaleFactor, defaultCssScaleFactor, dpi);
66   if (info.dwFlags & MONITORINFOF_PRIMARY) {
67     // The primary monitor must be the first element of the screen list.
68     screens->InsertElementAt(0, Move(screen));
69   } else {
70     screens->AppendElement(Move(screen));
71   }
72   return TRUE;
73 }
74 
RefreshScreens()75 void ScreenHelperWin::RefreshScreens() {
76   MOZ_LOG(sScreenLog, LogLevel::Debug, ("Refreshing screens"));
77 
78   AutoTArray<RefPtr<Screen>, 4> screens;
79   BOOL result = ::EnumDisplayMonitors(
80       nullptr, nullptr, (MONITORENUMPROC)CollectMonitors, (LPARAM)&screens);
81   if (!result) {
82     NS_WARNING("Unable to EnumDisplayMonitors");
83   }
84   ScreenManager& screenManager = ScreenManager::GetSingleton();
85   screenManager.Refresh(Move(screens));
86 }
87 
88 }  // namespace widget
89 }  // namespace mozilla
90