| // Copyright (c) 2012 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/screen_win.h" |
| |
| #include <windows.h> |
| |
| #include "base/hash.h" |
| #include "base/logging.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/win/win_util.h" |
| #include "ui/gfx/display.h" |
| #include "ui/gfx/win/dpi.h" |
| |
| namespace { |
| |
| MONITORINFOEX GetMonitorInfoForMonitor(HMONITOR monitor) { |
| MONITORINFOEX monitor_info; |
| ZeroMemory(&monitor_info, sizeof(MONITORINFOEX)); |
| monitor_info.cbSize = sizeof(monitor_info); |
| GetMonitorInfo(monitor, &monitor_info); |
| return monitor_info; |
| } |
| |
| gfx::Display GetDisplay(MONITORINFOEX& monitor_info) { |
| int64 id = static_cast<int64>( |
| base::Hash(base::WideToUTF8(monitor_info.szDevice))); |
| gfx::Rect bounds = gfx::Rect(monitor_info.rcMonitor); |
| gfx::Display display(id, bounds); |
| display.set_work_area(gfx::Rect(monitor_info.rcWork)); |
| display.SetScaleAndBounds(gfx::win::GetDeviceScaleFactor(), bounds); |
| |
| DEVMODE mode; |
| memset(&mode, 0, sizeof(DEVMODE)); |
| mode.dmSize = sizeof(DEVMODE); |
| mode.dmDriverExtra = 0; |
| if (EnumDisplaySettings(monitor_info.szDevice, |
| ENUM_CURRENT_SETTINGS, |
| &mode)) { |
| switch (mode.dmDisplayOrientation) { |
| case DMDO_DEFAULT: |
| display.set_rotation(gfx::Display::ROTATE_0); |
| break; |
| case DMDO_90: |
| display.set_rotation(gfx::Display::ROTATE_90); |
| break; |
| case DMDO_180: |
| display.set_rotation(gfx::Display::ROTATE_180); |
| break; |
| case DMDO_270: |
| display.set_rotation(gfx::Display::ROTATE_270); |
| break; |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| return display; |
| } |
| |
| BOOL CALLBACK EnumMonitorCallback(HMONITOR monitor, |
| HDC hdc, |
| LPRECT rect, |
| LPARAM data) { |
| std::vector<gfx::Display>* all_displays = |
| reinterpret_cast<std::vector<gfx::Display>*>(data); |
| DCHECK(all_displays); |
| |
| MONITORINFOEX monitor_info = GetMonitorInfoForMonitor(monitor); |
| gfx::Display display = GetDisplay(monitor_info); |
| all_displays->push_back(display); |
| return TRUE; |
| } |
| |
| std::vector<gfx::Display> GetDisplays() { |
| std::vector<gfx::Display> displays; |
| EnumDisplayMonitors(NULL, NULL, EnumMonitorCallback, |
| reinterpret_cast<LPARAM>(&displays)); |
| return displays; |
| } |
| |
| } // namespace |
| |
| namespace gfx { |
| |
| ScreenWin::ScreenWin() |
| : displays_(GetDisplays()) { |
| SingletonHwnd::GetInstance()->AddObserver(this); |
| } |
| |
| ScreenWin::~ScreenWin() { |
| SingletonHwnd::GetInstance()->RemoveObserver(this); |
| } |
| |
| bool ScreenWin::IsDIPEnabled() { |
| return IsInHighDPIMode(); |
| } |
| |
| gfx::Point ScreenWin::GetCursorScreenPoint() { |
| POINT pt; |
| GetCursorPos(&pt); |
| gfx::Point cursor_pos_pixels(pt); |
| return gfx::win::ScreenToDIPPoint(cursor_pos_pixels); |
| } |
| |
| gfx::NativeWindow ScreenWin::GetWindowUnderCursor() { |
| POINT cursor_loc; |
| HWND hwnd = GetCursorPos(&cursor_loc) ? WindowFromPoint(cursor_loc) : NULL; |
| return GetNativeWindowFromHWND(hwnd); |
| } |
| |
| gfx::NativeWindow ScreenWin::GetWindowAtScreenPoint(const gfx::Point& point) { |
| gfx::Point point_in_pixels = gfx::win::DIPToScreenPoint(point); |
| return GetNativeWindowFromHWND(WindowFromPoint(point_in_pixels.ToPOINT())); |
| } |
| |
| int ScreenWin::GetNumDisplays() const { |
| return GetSystemMetrics(SM_CMONITORS); |
| } |
| |
| std::vector<gfx::Display> ScreenWin::GetAllDisplays() const { |
| return displays_; |
| } |
| |
| gfx::Display ScreenWin::GetDisplayNearestWindow(gfx::NativeView window) const { |
| HWND window_hwnd = GetHWNDFromNativeView(window); |
| if (!window_hwnd) { |
| // When |window| isn't rooted to a display, we should just return the |
| // default display so we get some correct display information like the |
| // scaling factor. |
| return GetPrimaryDisplay(); |
| } |
| |
| MONITORINFOEX monitor_info; |
| monitor_info.cbSize = sizeof(monitor_info); |
| GetMonitorInfo(MonitorFromWindow(window_hwnd, MONITOR_DEFAULTTONEAREST), |
| &monitor_info); |
| return GetDisplay(monitor_info); |
| } |
| |
| gfx::Display ScreenWin::GetDisplayNearestPoint(const gfx::Point& point) const { |
| POINT initial_loc = { point.x(), point.y() }; |
| HMONITOR monitor = MonitorFromPoint(initial_loc, MONITOR_DEFAULTTONEAREST); |
| MONITORINFOEX mi; |
| ZeroMemory(&mi, sizeof(MONITORINFOEX)); |
| mi.cbSize = sizeof(mi); |
| if (monitor && GetMonitorInfo(monitor, &mi)) { |
| return GetDisplay(mi); |
| } |
| return gfx::Display(); |
| } |
| |
| gfx::Display ScreenWin::GetDisplayMatching(const gfx::Rect& match_rect) const { |
| RECT other_bounds_rect = match_rect.ToRECT(); |
| MONITORINFOEX monitor_info = GetMonitorInfoForMonitor(MonitorFromRect( |
| &other_bounds_rect, MONITOR_DEFAULTTONEAREST)); |
| return GetDisplay(monitor_info); |
| } |
| |
| gfx::Display ScreenWin::GetPrimaryDisplay() const { |
| MONITORINFOEX mi = GetMonitorInfoForMonitor( |
| MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY)); |
| gfx::Display display = GetDisplay(mi); |
| // TODO(kevers|girard): Test if these checks can be reintroduced for high-DIP |
| // once more of the app is DIP-aware. |
| if (!(IsInHighDPIMode() || IsHighDPIEnabled())) { |
| DCHECK_EQ(GetSystemMetrics(SM_CXSCREEN), display.size().width()); |
| DCHECK_EQ(GetSystemMetrics(SM_CYSCREEN), display.size().height()); |
| } |
| return display; |
| } |
| |
| void ScreenWin::AddObserver(DisplayObserver* observer) { |
| change_notifier_.AddObserver(observer); |
| } |
| |
| void ScreenWin::RemoveObserver(DisplayObserver* observer) { |
| change_notifier_.RemoveObserver(observer); |
| } |
| |
| void ScreenWin::OnWndProc(HWND hwnd, |
| UINT message, |
| WPARAM wparam, |
| LPARAM lparam) { |
| if (message != WM_DISPLAYCHANGE) |
| return; |
| |
| std::vector<gfx::Display> old_displays = displays_; |
| displays_ = GetDisplays(); |
| |
| change_notifier_.NotifyDisplaysChanged(old_displays, displays_); |
| } |
| |
| HWND ScreenWin::GetHWNDFromNativeView(NativeView window) const { |
| NOTREACHED(); |
| return NULL; |
| } |
| |
| NativeWindow ScreenWin::GetNativeWindowFromHWND(HWND hwnd) const { |
| NOTREACHED(); |
| return NULL; |
| } |
| |
| } // namespace gfx |