Chromium Code Reviews| Index: ui/gfx/win/display_manager.cc |
| diff --git a/ui/gfx/win/display_manager.cc b/ui/gfx/win/display_manager.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..c1c34d87ff2e1b5656d8b0b10c12ac231fab6267 |
| --- /dev/null |
| +++ b/ui/gfx/win/display_manager.cc |
| @@ -0,0 +1,191 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "ui/gfx/win/display_manager.h" |
| + |
| +#include <windows.h> |
| + |
| +#include "base/bind.h" |
| +#include "base/bind_helpers.h" |
| +#include "base/lazy_instance.h" |
| +#include "base/memory/scoped_ptr.h" |
| +#include "ui/gfx/win/display_info.h" |
| +#include "ui/gfx/win/display_manager_observer.h" |
| +#include "ui/gfx/win/dpi.h" |
| +#include "ui/gfx/win/screen_win_display.h" |
| +#include "ui/gfx/win/singleton_hwnd_observer.h" |
| + |
| +namespace { |
| + |
| +// Use Leaky since gfx::ScreenWin is leaked at exit, and LazyInstance instead of |
| +// Singleton allows for a substitution for testing. |
| +base::LazyInstance<scoped_ptr<gfx::win::DisplayManager>>::Leaky |
| + g_display_manager = LAZY_INSTANCE_INITIALIZER; |
| + |
| +MONITORINFOEX MonitorInfoFromHMONITOR(HMONITOR monitor) { |
| + MONITORINFOEX monitor_info; |
| + ::ZeroMemory(&monitor_info, sizeof(monitor_info)); |
| + monitor_info.cbSize = sizeof(monitor_info); |
| + ::GetMonitorInfo(monitor, &monitor_info); |
| + return monitor_info; |
| +} |
| + |
| +BOOL CALLBACK EnumMonitorCallback(HMONITOR monitor, |
| + HDC hdc, |
| + LPRECT rect, |
| + LPARAM data) { |
| + std::vector<gfx::win::DisplayInfo>* display_infos = |
| + reinterpret_cast<std::vector<gfx::win::DisplayInfo>*>(data); |
| + DCHECK(display_infos); |
| + display_infos->push_back( |
| + gfx::win::DisplayInfo(MonitorInfoFromHMONITOR(monitor), |
| + gfx::GetDPIScale())); |
| + return TRUE; |
| +} |
| + |
| +std::vector<gfx::win::DisplayInfo> GetDisplayInfosFromSystem() { |
| + std::vector<gfx::win::DisplayInfo> display_infos; |
| + EnumDisplayMonitors(NULL, NULL, EnumMonitorCallback, |
| + reinterpret_cast<LPARAM>(&display_infos)); |
| + DCHECK_EQ(static_cast<size_t>(::GetSystemMetrics(SM_CMONITORS)), |
| + display_infos.size()); |
| + return display_infos; |
| +} |
| + |
| +std::vector<gfx::win::ScreenWinDisplay> DisplayInfosToScreenWinDisplays( |
| + const std::vector<gfx::win::DisplayInfo>& display_infos) { |
| + std::vector<gfx::win::ScreenWinDisplay> screen_win_displays; |
| + for (const auto& display_info : display_infos) |
| + screen_win_displays.push_back(gfx::win::ScreenWinDisplay(display_info)); |
| + |
| + return screen_win_displays; |
| +} |
| + |
| +} // namespace |
| + |
| +namespace gfx { |
| +namespace win { |
| + |
| +// static |
| +DisplayManager* DisplayManager::GetInstance() { |
| + if (!g_display_manager.Get().get()) { |
| + g_display_manager.Get().reset(new DisplayManager()); |
| + g_display_manager.Get()->Initialize(); |
| + } |
| + return g_display_manager.Get().get(); |
| +} |
| + |
| +void DisplayManager::Initialize() { |
| + singleton_hwnd_observer_.reset( |
| + new gfx::SingletonHwndObserver( |
| + base::Bind(&DisplayManager::WndProc, base::Unretained(this)))); |
| + UpdateFromDisplayInfos(GetDisplayInfosFromSystem()); |
| +} |
| + |
| +void DisplayManager::AddObserver(DisplayManagerObserver* observer) { |
| + observer_list_.AddObserver(observer); |
| +} |
| + |
| +void DisplayManager::RemoveObserver(DisplayManagerObserver* observer) { |
| + observer_list_.RemoveObserver(observer); |
| +} |
| + |
| +const std::vector<ScreenWinDisplay>& DisplayManager::GetScreenWinDisplays() { |
| + return screen_win_displays_; |
| +} |
| + |
| +ScreenWinDisplay DisplayManager::GetScreenWinDisplayNearestHWND(HWND hwnd) |
| + const { |
| + return GetScreenWinDisplay(MonitorInfoFromWindow(hwnd, |
| + MONITOR_DEFAULTTONEAREST)); |
| +} |
| + |
| +ScreenWinDisplay DisplayManager::GetScreenWinDisplayNearestScreenRect( |
| + const Rect& screen_rect) const { |
| + return GetScreenWinDisplay(MonitorInfoFromScreenRect(screen_rect)); |
| +} |
| + |
| +ScreenWinDisplay DisplayManager::GetScreenWinDisplayNearestScreenPoint( |
| + const Point& screen_point) const { |
| + return GetScreenWinDisplay(MonitorInfoFromScreenPoint(screen_point)); |
| +} |
| + |
| +ScreenWinDisplay DisplayManager::GetPrimaryScreenWinDisplay() const { |
| + MONITORINFOEX monitor_info = MonitorInfoFromWindow(NULL, |
| + MONITOR_DEFAULTTOPRIMARY); |
| + ScreenWinDisplay screen_win_display = GetScreenWinDisplay(monitor_info); |
| + gfx::Display display = screen_win_display.display(); |
| + // The Windows primary monitor is defined to have an origin of (0, 0). |
| + DCHECK_EQ(0, display.bounds().origin().x()); |
| + DCHECK_EQ(0, display.bounds().origin().y()); |
| + return screen_win_display; |
| +} |
| + |
| +MONITORINFOEX DisplayManager::MonitorInfoFromScreenPoint( |
| + const gfx::Point& screen_point) const { |
| + POINT initial_loc = { screen_point.x(), screen_point.y() }; |
| + return MonitorInfoFromHMONITOR(::MonitorFromPoint(initial_loc, |
| + MONITOR_DEFAULTTONEAREST)); |
| +} |
| + |
| +MONITORINFOEX DisplayManager::MonitorInfoFromScreenRect( |
| + const gfx::Rect& screen_rect) const { |
| + RECT win_rect = screen_rect.ToRECT(); |
| + return MonitorInfoFromHMONITOR(::MonitorFromRect(&win_rect, |
| + MONITOR_DEFAULTTONEAREST)); |
| +} |
| + |
| +MONITORINFOEX DisplayManager::MonitorInfoFromWindow( |
| + HWND hwnd, DWORD default_options) const { |
| + return MonitorInfoFromHMONITOR(::MonitorFromWindow(hwnd, |
| + default_options)); |
|
oshima
2016/01/30 00:10:33
fit to single line?
robliao
2016/01/30 01:23:52
Done.
|
| +} |
| + |
| +HWND DisplayManager::GetRootWindow(HWND hwnd) const { |
| + return ::GetAncestor(hwnd, GA_ROOT); |
| +} |
| + |
| +// static |
| +void DisplayManager::SetInstanceForTesting( |
| + scoped_ptr<DisplayManager> display_manager) { |
| + g_display_manager.Get() = std::move(display_manager); |
| +} |
| + |
| +DisplayManager::DisplayManager() = default; |
| + |
| +DisplayManager::~DisplayManager() = default; |
| + |
| +void DisplayManager::UpdateFromDisplayInfos( |
| + const std::vector<DisplayInfo>& display_infos) { |
| + screen_win_displays_ = DisplayInfosToScreenWinDisplays(display_infos); |
| +} |
| + |
| +ScreenWinDisplay DisplayManager::GetScreenWinDisplay( |
| + const MONITORINFOEX& monitor_info) const { |
| + int64_t id = DisplayInfo::HashDeviceName(monitor_info.szDevice); |
| + for (const auto& screen_win_display : screen_win_displays_) { |
| + if (screen_win_display.display().id() == id) |
| + return screen_win_display; |
| + } |
| + // When the system isn't initialized, it means we're likely under a test. |
| + DCHECK_EQ(screen_win_displays_.size(), 0u); |
| + return ScreenWinDisplay(); |
| +} |
| + |
| +void DisplayManager::WndProc(HWND hwnd, |
| + UINT message, |
| + WPARAM wparam,LPARAM lparam) { |
| + if (message != WM_DISPLAYCHANGE) |
| + return; |
| + |
| + std::vector<ScreenWinDisplay> old_displays = screen_win_displays_; |
| + UpdateFromDisplayInfos(GetDisplayInfosFromSystem()); |
| + |
| + FOR_EACH_OBSERVER(DisplayManagerObserver, |
| + observer_list_, |
| + OnDisplaysChanged(old_displays, screen_win_displays_)); |
| +} |
| + |
| +} // namespace win |
| +} // namespace gfx |