1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "ui/gfx/screen_win.h" 6 7#include <windows.h> 8 9#include "base/hash.h" 10#include "base/logging.h" 11#include "base/strings/utf_string_conversions.h" 12#include "base/win/win_util.h" 13#include "ui/gfx/display.h" 14#include "ui/gfx/win/dpi.h" 15 16namespace { 17 18MONITORINFOEX GetMonitorInfoForMonitor(HMONITOR monitor) { 19 MONITORINFOEX monitor_info; 20 ZeroMemory(&monitor_info, sizeof(MONITORINFOEX)); 21 monitor_info.cbSize = sizeof(monitor_info); 22 GetMonitorInfo(monitor, &monitor_info); 23 return monitor_info; 24} 25 26gfx::Display GetDisplay(MONITORINFOEX& monitor_info) { 27 int64 id = static_cast<int64>( 28 base::Hash(base::WideToUTF8(monitor_info.szDevice))); 29 gfx::Rect bounds = gfx::Rect(monitor_info.rcMonitor); 30 gfx::Display display(id, bounds); 31 display.set_work_area(gfx::Rect(monitor_info.rcWork)); 32 display.SetScaleAndBounds(gfx::win::GetDeviceScaleFactor(), bounds); 33 34 DEVMODE mode; 35 memset(&mode, 0, sizeof(DEVMODE)); 36 mode.dmSize = sizeof(DEVMODE); 37 mode.dmDriverExtra = 0; 38 if (EnumDisplaySettings(monitor_info.szDevice, 39 ENUM_CURRENT_SETTINGS, 40 &mode)) { 41 switch (mode.dmDisplayOrientation) { 42 case DMDO_DEFAULT: 43 display.set_rotation(gfx::Display::ROTATE_0); 44 break; 45 case DMDO_90: 46 display.set_rotation(gfx::Display::ROTATE_90); 47 break; 48 case DMDO_180: 49 display.set_rotation(gfx::Display::ROTATE_180); 50 break; 51 case DMDO_270: 52 display.set_rotation(gfx::Display::ROTATE_270); 53 break; 54 default: 55 NOTREACHED(); 56 } 57 } 58 59 return display; 60} 61 62BOOL CALLBACK EnumMonitorCallback(HMONITOR monitor, 63 HDC hdc, 64 LPRECT rect, 65 LPARAM data) { 66 std::vector<gfx::Display>* all_displays = 67 reinterpret_cast<std::vector<gfx::Display>*>(data); 68 DCHECK(all_displays); 69 70 MONITORINFOEX monitor_info = GetMonitorInfoForMonitor(monitor); 71 gfx::Display display = GetDisplay(monitor_info); 72 all_displays->push_back(display); 73 return TRUE; 74} 75 76std::vector<gfx::Display> GetDisplays() { 77 std::vector<gfx::Display> displays; 78 EnumDisplayMonitors(NULL, NULL, EnumMonitorCallback, 79 reinterpret_cast<LPARAM>(&displays)); 80 return displays; 81} 82 83} // namespace 84 85namespace gfx { 86 87ScreenWin::ScreenWin() 88 : displays_(GetDisplays()) { 89 SingletonHwnd::GetInstance()->AddObserver(this); 90} 91 92ScreenWin::~ScreenWin() { 93 SingletonHwnd::GetInstance()->RemoveObserver(this); 94} 95 96bool ScreenWin::IsDIPEnabled() { 97 return IsInHighDPIMode(); 98} 99 100gfx::Point ScreenWin::GetCursorScreenPoint() { 101 POINT pt; 102 GetCursorPos(&pt); 103 gfx::Point cursor_pos_pixels(pt); 104 return gfx::win::ScreenToDIPPoint(cursor_pos_pixels); 105} 106 107gfx::NativeWindow ScreenWin::GetWindowUnderCursor() { 108 POINT cursor_loc; 109 HWND hwnd = GetCursorPos(&cursor_loc) ? WindowFromPoint(cursor_loc) : NULL; 110 return GetNativeWindowFromHWND(hwnd); 111} 112 113gfx::NativeWindow ScreenWin::GetWindowAtScreenPoint(const gfx::Point& point) { 114 gfx::Point point_in_pixels = gfx::win::DIPToScreenPoint(point); 115 return GetNativeWindowFromHWND(WindowFromPoint(point_in_pixels.ToPOINT())); 116} 117 118int ScreenWin::GetNumDisplays() const { 119 return GetSystemMetrics(SM_CMONITORS); 120} 121 122std::vector<gfx::Display> ScreenWin::GetAllDisplays() const { 123 return displays_; 124} 125 126gfx::Display ScreenWin::GetDisplayNearestWindow(gfx::NativeView window) const { 127 HWND window_hwnd = GetHWNDFromNativeView(window); 128 if (!window_hwnd) { 129 // When |window| isn't rooted to a display, we should just return the 130 // default display so we get some correct display information like the 131 // scaling factor. 132 return GetPrimaryDisplay(); 133 } 134 135 MONITORINFOEX monitor_info; 136 monitor_info.cbSize = sizeof(monitor_info); 137 GetMonitorInfo(MonitorFromWindow(window_hwnd, MONITOR_DEFAULTTONEAREST), 138 &monitor_info); 139 return GetDisplay(monitor_info); 140} 141 142gfx::Display ScreenWin::GetDisplayNearestPoint(const gfx::Point& point) const { 143 POINT initial_loc = { point.x(), point.y() }; 144 HMONITOR monitor = MonitorFromPoint(initial_loc, MONITOR_DEFAULTTONEAREST); 145 MONITORINFOEX mi; 146 ZeroMemory(&mi, sizeof(MONITORINFOEX)); 147 mi.cbSize = sizeof(mi); 148 if (monitor && GetMonitorInfo(monitor, &mi)) { 149 return GetDisplay(mi); 150 } 151 return gfx::Display(); 152} 153 154gfx::Display ScreenWin::GetDisplayMatching(const gfx::Rect& match_rect) const { 155 RECT other_bounds_rect = match_rect.ToRECT(); 156 MONITORINFOEX monitor_info = GetMonitorInfoForMonitor(MonitorFromRect( 157 &other_bounds_rect, MONITOR_DEFAULTTONEAREST)); 158 return GetDisplay(monitor_info); 159} 160 161gfx::Display ScreenWin::GetPrimaryDisplay() const { 162 MONITORINFOEX mi = GetMonitorInfoForMonitor( 163 MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY)); 164 gfx::Display display = GetDisplay(mi); 165 // TODO(kevers|girard): Test if these checks can be reintroduced for high-DIP 166 // once more of the app is DIP-aware. 167 if (!(IsInHighDPIMode() || IsHighDPIEnabled())) { 168 DCHECK_EQ(GetSystemMetrics(SM_CXSCREEN), display.size().width()); 169 DCHECK_EQ(GetSystemMetrics(SM_CYSCREEN), display.size().height()); 170 } 171 return display; 172} 173 174void ScreenWin::AddObserver(DisplayObserver* observer) { 175 change_notifier_.AddObserver(observer); 176} 177 178void ScreenWin::RemoveObserver(DisplayObserver* observer) { 179 change_notifier_.RemoveObserver(observer); 180} 181 182void ScreenWin::OnWndProc(HWND hwnd, 183 UINT message, 184 WPARAM wparam, 185 LPARAM lparam) { 186 if (message != WM_DISPLAYCHANGE) 187 return; 188 189 std::vector<gfx::Display> old_displays = displays_; 190 displays_ = GetDisplays(); 191 192 change_notifier_.NotifyDisplaysChanged(old_displays, displays_); 193} 194 195HWND ScreenWin::GetHWNDFromNativeView(NativeView window) const { 196 NOTREACHED(); 197 return NULL; 198} 199 200NativeWindow ScreenWin::GetNativeWindowFromHWND(HWND hwnd) const { 201 NOTREACHED(); 202 return NULL; 203} 204 205} // namespace gfx 206