OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/screen_win.h" | 5 #include "ui/gfx/screen_win.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
12 #include "base/hash.h" | 12 #include "base/hash.h" |
13 #include "base/logging.h" | 13 #include "base/logging.h" |
14 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
15 #include "base/win/win_util.h" | 15 #include "base/win/win_util.h" |
16 #include "ui/gfx/display.h" | 16 #include "ui/gfx/display.h" |
| 17 #include "ui/gfx/geometry/insets.h" |
| 18 #include "ui/gfx/geometry/point.h" |
| 19 #include "ui/gfx/geometry/point_conversions.h" |
| 20 #include "ui/gfx/geometry/rect.h" |
| 21 #include "ui/gfx/geometry/safe_integer_conversions.h" |
| 22 #include "ui/gfx/geometry/size.h" |
| 23 #include "ui/gfx/geometry/vector2d.h" |
17 #include "ui/gfx/win/dpi.h" | 24 #include "ui/gfx/win/dpi.h" |
| 25 #include "ui/gfx/win/rect_util.h" |
18 | 26 |
19 namespace { | 27 namespace { |
20 | 28 |
21 MONITORINFOEX GetMonitorInfoForMonitor(HMONITOR monitor) { | 29 gfx::Display::Rotation GetRotationForDevice(const wchar_t* device_name) { |
22 MONITORINFOEX monitor_info; | |
23 ZeroMemory(&monitor_info, sizeof(MONITORINFOEX)); | |
24 monitor_info.cbSize = sizeof(monitor_info); | |
25 GetMonitorInfo(monitor, &monitor_info); | |
26 return monitor_info; | |
27 } | |
28 | |
29 gfx::Display GetDisplay(const MONITORINFOEX& monitor_info) { | |
30 int64_t id = | |
31 static_cast<int64_t>(base::Hash(base::WideToUTF8(monitor_info.szDevice))); | |
32 gfx::Rect bounds = gfx::Rect(monitor_info.rcMonitor); | |
33 gfx::Display display(id); | |
34 display.set_bounds(gfx::win::ScreenToDIPRect(bounds)); | |
35 display.set_work_area( | |
36 gfx::win::ScreenToDIPRect(gfx::Rect(monitor_info.rcWork))); | |
37 display.SetScaleAndBounds(gfx::GetDPIScale(), bounds); | |
38 | |
39 DEVMODE mode; | 30 DEVMODE mode; |
40 memset(&mode, 0, sizeof(DEVMODE)); | 31 ::ZeroMemory(&mode, sizeof(mode)); |
41 mode.dmSize = sizeof(DEVMODE); | 32 mode.dmSize = sizeof(DEVMODE); |
42 mode.dmDriverExtra = 0; | 33 mode.dmDriverExtra = 0; |
43 if (EnumDisplaySettings(monitor_info.szDevice, | 34 if (::EnumDisplaySettings(device_name, ENUM_CURRENT_SETTINGS, &mode)) { |
44 ENUM_CURRENT_SETTINGS, | |
45 &mode)) { | |
46 switch (mode.dmDisplayOrientation) { | 35 switch (mode.dmDisplayOrientation) { |
47 case DMDO_DEFAULT: | 36 case DMDO_DEFAULT: |
48 display.set_rotation(gfx::Display::ROTATE_0); | 37 return gfx::Display::ROTATE_0; |
49 break; | |
50 case DMDO_90: | 38 case DMDO_90: |
51 display.set_rotation(gfx::Display::ROTATE_90); | 39 return gfx::Display::ROTATE_90; |
52 break; | |
53 case DMDO_180: | 40 case DMDO_180: |
54 display.set_rotation(gfx::Display::ROTATE_180); | 41 return gfx::Display::ROTATE_180; |
55 break; | |
56 case DMDO_270: | 42 case DMDO_270: |
57 display.set_rotation(gfx::Display::ROTATE_270); | 43 return gfx::Display::ROTATE_270; |
58 break; | |
59 default: | 44 default: |
60 NOTREACHED(); | 45 NOTREACHED(); |
61 } | 46 } |
62 } | 47 } |
63 | 48 return gfx::Display::ROTATE_0; |
64 return display; | |
65 } | 49 } |
66 | 50 |
67 BOOL CALLBACK EnumMonitorCallback(HMONITOR monitor, | 51 // Returns a point in |to_origin|'s coordinates and position scaled by |
68 HDC hdc, | 52 // |scale_factor|. |
69 LPRECT rect, | 53 gfx::Point ScalePointRelative(const gfx::Point& from_origin, |
70 LPARAM data) { | 54 const gfx::Point& to_origin, |
71 std::vector<gfx::Display>* all_displays = | 55 const float scale_factor, |
72 reinterpret_cast<std::vector<gfx::Display>*>(data); | 56 const gfx::Point& point) { |
73 DCHECK(all_displays); | 57 gfx::Vector2d from_origin_vector(from_origin.x(), from_origin.y()); |
74 | 58 gfx::Vector2d to_origin_vector(to_origin.x(), to_origin.y()); |
75 MONITORINFOEX monitor_info = GetMonitorInfoForMonitor(monitor); | 59 return gfx::ScaleToFlooredPoint(point - from_origin_vector, scale_factor) + |
76 gfx::Display display = GetDisplay(monitor_info); | 60 to_origin_vector; |
77 all_displays->push_back(display); | |
78 return TRUE; | |
79 } | 61 } |
80 | 62 |
81 std::vector<gfx::Display> GetDisplays() { | 63 // Returns the NativeScreen. For all intents and purposes, this screen provides |
82 std::vector<gfx::Display> displays; | 64 // the source of truth for displays in Windows. |
83 EnumDisplayMonitors(NULL, NULL, EnumMonitorCallback, | 65 gfx::ScreenWin* GetNativeScreenWin() { |
84 reinterpret_cast<LPARAM>(&displays)); | 66 return static_cast<gfx::ScreenWin*>(gfx::Screen::GetNativeScreen()); |
85 return displays; | 67 } |
| 68 |
| 69 // static |
| 70 MONITORINFOEX MonitorInfoFromHMONITOR(HMONITOR monitor) { |
| 71 MONITORINFOEX monitor_info; |
| 72 ::ZeroMemory(&monitor_info, sizeof(monitor_info)); |
| 73 monitor_info.cbSize = sizeof(monitor_info); |
| 74 ::GetMonitorInfo(monitor, &monitor_info); |
| 75 return monitor_info; |
86 } | 76 } |
87 | 77 |
88 } // namespace | 78 } // namespace |
89 | 79 |
90 namespace gfx { | 80 namespace gfx { |
91 | 81 |
| 82 class ScreenWin::DisplayWin { |
| 83 public: |
| 84 explicit DisplayWin(); |
| 85 explicit DisplayWin(const DisplayInfo& display_info); |
| 86 DisplayWin(const DisplayWin& ref, const DisplayInfo& display_info); |
| 87 |
| 88 const Display& display() const { return display_; } |
| 89 const Rect& physical_bounds() const { return pixel_bounds_; } |
| 90 |
| 91 private: |
| 92 Display display_; |
| 93 Rect pixel_bounds_; |
| 94 }; |
| 95 |
92 ScreenWin::ScreenWin() | 96 ScreenWin::ScreenWin() |
93 : singleton_hwnd_observer_(new SingletonHwndObserver( | 97 : singleton_hwnd_observer_(new SingletonHwndObserver( |
94 base::Bind(&ScreenWin::OnWndProc, base::Unretained(this)))), | 98 base::Bind(&ScreenWin::OnWndProc, base::Unretained(this)))), |
95 displays_(GetDisplays()) { | 99 display_wins_(GetDisplayWins()) {} |
| 100 |
| 101 ScreenWin::~ScreenWin() {} |
| 102 |
| 103 // static |
| 104 Point ScreenWin::ScreenToDIPPoint(const Point& pixel_point) { |
| 105 DisplayWin display_win = GetDisplayNearestScreenPoint(pixel_point); |
| 106 Display display = display_win.display(); |
| 107 return ScalePointRelative(display_win.physical_bounds().origin(), |
| 108 display.bounds().origin(), |
| 109 1.0f / display.device_scale_factor(), |
| 110 pixel_point); |
96 } | 111 } |
97 | 112 |
98 ScreenWin::~ScreenWin() {} | 113 // static |
| 114 Point ScreenWin::DIPToScreenPoint(const Point& dip_point) { |
| 115 DisplayWin display_win = GetDisplayNearestDIPPoint(dip_point); |
| 116 Display display = display_win.display(); |
| 117 return ScalePointRelative(display.bounds().origin(), |
| 118 display_win.physical_bounds().origin(), |
| 119 display.device_scale_factor(), |
| 120 dip_point); |
| 121 } |
| 122 |
| 123 |
| 124 Point ScreenWin::ClientToDIPPoint(HWND hwnd, const Point& client_point) { |
| 125 return ScaleToFlooredPoint(client_point, 1.0f / GetScaleFactorForHWND(hwnd)); |
| 126 } |
| 127 |
| 128 Point ScreenWin::DIPToClientPoint(HWND hwnd, const Point& dip_point) { |
| 129 return ScaleToFlooredPoint(dip_point, GetScaleFactorForHWND(hwnd)); |
| 130 } |
| 131 |
| 132 // static |
| 133 Rect ScreenWin::ScreenToDIPRect(HWND hwnd, const Rect& pixel_bounds) { |
| 134 // It's important we scale the origin and size separately. If we instead |
| 135 // calculated the size from the floored origin and ceiled right the size could |
| 136 // vary depending upon where the two points land. That would cause problems |
| 137 // for the places this code is used (in particular mapping from native window |
| 138 // bounds to DIPs). |
| 139 if (hwnd) { |
| 140 return Rect(ScreenToDIPPoint(pixel_bounds.origin()), |
| 141 ScreenToDIPSize(hwnd, pixel_bounds.size())); |
| 142 } |
| 143 float scale_factor = |
| 144 GetDisplayNearestScreenRect(pixel_bounds).display().device_scale_factor(); |
| 145 return Rect(ScreenToDIPPoint(pixel_bounds.origin()), |
| 146 ScaleToCeiledSize(pixel_bounds.size(), 1.0f / scale_factor)); |
| 147 } |
| 148 |
| 149 // static |
| 150 Rect ScreenWin::DIPToScreenRect(HWND hwnd, const Rect& dip_bounds) { |
| 151 // See comment in ScreenToDIPRect for why we calculate size like this. |
| 152 if (hwnd) { |
| 153 return Rect(DIPToScreenPoint(dip_bounds.origin()), |
| 154 DIPToScreenSize(hwnd, dip_bounds.size())); |
| 155 } |
| 156 // Because origins don't change for screen points and scaling factors are |
| 157 // greater than 1, the monitor bounding rect always contains the DIP point. |
| 158 float scale_factor = |
| 159 GetDisplayNearestDIPRect(dip_bounds).display().device_scale_factor(); |
| 160 return Rect(DIPToScreenPoint(dip_bounds.origin()), |
| 161 ScaleToCeiledSize(dip_bounds.size(), scale_factor)); |
| 162 } |
| 163 |
| 164 // static |
| 165 Rect ScreenWin::ClientToDIPRect(HWND hwnd, const Rect& pixel_bounds) { |
| 166 // See comment in ScreenToDIPRect for why we calculate size like this. |
| 167 return Rect(ClientToDIPPoint(hwnd, pixel_bounds.origin()), |
| 168 ScreenToDIPSize(hwnd, pixel_bounds.size())); |
| 169 } |
| 170 |
| 171 // static |
| 172 Rect ScreenWin::DIPToClientRect(HWND hwnd, const Rect& dip_bounds) { |
| 173 // See comment in ScreenToDIPRect for why we calculate size like this. |
| 174 return Rect(DIPToClientPoint(hwnd, dip_bounds.origin()), |
| 175 DIPToScreenSize(hwnd, dip_bounds.size())); |
| 176 } |
| 177 |
| 178 // static |
| 179 Size ScreenWin::ScreenToDIPSize(HWND hwnd, const Size& size_in_pixels) { |
| 180 // Always ceil sizes. Otherwise we may be leaving off part of the bounds. |
| 181 return ScaleToCeiledSize(size_in_pixels, 1.0f / GetScaleFactorForHWND(hwnd)); |
| 182 } |
| 183 |
| 184 // static |
| 185 Size ScreenWin::DIPToScreenSize(HWND hwnd, const Size& dip_size) { |
| 186 // Always ceil sizes. Otherwise we may be leaving off part of the bounds. |
| 187 return ScaleToCeiledSize(dip_size, GetScaleFactorForHWND(hwnd)); |
| 188 } |
99 | 189 |
100 HWND ScreenWin::GetHWNDFromNativeView(NativeView window) const { | 190 HWND ScreenWin::GetHWNDFromNativeView(NativeView window) const { |
101 NOTREACHED(); | 191 NOTREACHED(); |
102 return NULL; | 192 return NULL; |
103 } | 193 } |
104 | 194 |
105 NativeWindow ScreenWin::GetNativeWindowFromHWND(HWND hwnd) const { | 195 NativeWindow ScreenWin::GetNativeWindowFromHWND(HWND hwnd) const { |
106 NOTREACHED(); | 196 NOTREACHED(); |
107 return NULL; | 197 return NULL; |
108 } | 198 } |
109 | 199 |
| 200 ScreenWin::DisplayInfo::DisplayInfo(HMONITOR monitor, |
| 201 float device_scale_factor) : |
| 202 device_scale_factor_(device_scale_factor){ |
| 203 MONITORINFOEX monitor_info; |
| 204 ::ZeroMemory(&monitor_info, sizeof(monitor_info)); |
| 205 monitor_info.cbSize = sizeof(monitor_info); |
| 206 ::GetMonitorInfo(monitor, &monitor_info); |
| 207 InitializeFromMonitorInfo(monitor_info); |
| 208 } |
| 209 |
| 210 ScreenWin::DisplayInfo::DisplayInfo(const MONITORINFOEX& monitor_info, |
| 211 gfx::Display::Rotation rotation, |
| 212 float device_scale_factor) |
| 213 : rotation_(rotation), |
| 214 device_scale_factor_(device_scale_factor) { |
| 215 InitializeFromMonitorInfo(monitor_info); |
| 216 } |
| 217 |
| 218 void ScreenWin::DisplayInfo::InitializeFromMonitorInfo( |
| 219 const MONITORINFOEX& monitor_info) { |
| 220 id_ = ScreenWin::HashDeviceName(monitor_info.szDevice); |
| 221 screen_rect_ = gfx::Rect(monitor_info.rcMonitor); |
| 222 screen_work_rect_ = gfx::Rect(monitor_info.rcWork); |
| 223 rotation_ = GetRotationForDevice(monitor_info.szDevice); |
| 224 } |
| 225 |
| 226 ScreenWin::ScreenWin(const std::vector<ScreenWin::DisplayInfo>& display_infos) { |
| 227 display_wins_ = GetDisplaysFromDisplayInfos(display_infos); |
| 228 } |
| 229 |
| 230 int64_t ScreenWin::HashDeviceName(const wchar_t* device_name) { |
| 231 return static_cast<int64_t>(base::Hash(base::WideToUTF8(device_name))); |
| 232 } |
| 233 |
110 gfx::Point ScreenWin::GetCursorScreenPoint() { | 234 gfx::Point ScreenWin::GetCursorScreenPoint() { |
111 POINT pt; | 235 POINT pt; |
112 GetCursorPos(&pt); | 236 GetCursorPos(&pt); |
113 gfx::Point cursor_pos_pixels(pt); | 237 gfx::Point cursor_pos_pixels(pt); |
114 return gfx::win::ScreenToDIPPoint(cursor_pos_pixels); | 238 return ScreenToDIPPoint(cursor_pos_pixels); |
115 } | 239 } |
116 | 240 |
117 gfx::NativeWindow ScreenWin::GetWindowUnderCursor() { | 241 gfx::NativeWindow ScreenWin::GetWindowUnderCursor() { |
118 POINT cursor_loc; | 242 POINT cursor_loc; |
119 HWND hwnd = GetCursorPos(&cursor_loc) ? WindowFromPoint(cursor_loc) : NULL; | 243 HWND hwnd = GetCursorPos(&cursor_loc) ? WindowFromPoint(cursor_loc) : NULL; |
120 return GetNativeWindowFromHWND(hwnd); | 244 return GetNativeWindowFromHWND(hwnd); |
121 } | 245 } |
122 | 246 |
123 gfx::NativeWindow ScreenWin::GetWindowAtScreenPoint(const gfx::Point& point) { | 247 gfx::NativeWindow ScreenWin::GetWindowAtScreenPoint(const gfx::Point& point) { |
124 gfx::Point point_in_pixels = gfx::win::DIPToScreenPoint(point); | 248 gfx::Point point_in_pixels = DIPToScreenPoint(point); |
125 return GetNativeWindowFromHWND(WindowFromPoint(point_in_pixels.ToPOINT())); | 249 return GetNativeWindowFromHWND(WindowFromPoint(point_in_pixels.ToPOINT())); |
126 } | 250 } |
127 | 251 |
128 int ScreenWin::GetNumDisplays() const { | 252 int ScreenWin::GetNumDisplays() const { |
129 return GetSystemMetrics(SM_CMONITORS); | 253 return GetSystemMetrics(SM_CMONITORS); |
130 } | 254 } |
131 | 255 |
132 std::vector<gfx::Display> ScreenWin::GetAllDisplays() const { | 256 std::vector<gfx::Display> ScreenWin::GetAllDisplays() const { |
133 return displays_; | 257 std::vector<gfx::Display> displays; |
| 258 for (const DisplayWin& display_win : display_wins_) { |
| 259 displays.push_back(display_win.display()); |
| 260 } |
| 261 return displays; |
134 } | 262 } |
135 | 263 |
136 gfx::Display ScreenWin::GetDisplayNearestWindow(gfx::NativeView window) const { | 264 gfx::Display ScreenWin::GetDisplayNearestWindow(gfx::NativeView window) const { |
137 HWND window_hwnd = GetHWNDFromNativeView(window); | 265 HWND window_hwnd = GetHWNDFromNativeView(window); |
138 if (!window_hwnd) { | 266 if (!window_hwnd) { |
139 // When |window| isn't rooted to a display, we should just return the | 267 // When |window| isn't rooted to a display, we should just return the |
140 // default display so we get some correct display information like the | 268 // default display so we get some correct display information like the |
141 // scaling factor. | 269 // scaling factor. |
142 return GetPrimaryDisplay(); | 270 return GetPrimaryDisplay(); |
143 } | 271 } |
144 | 272 return GetDisplayNearestHWND(window_hwnd).display(); |
145 MONITORINFOEX monitor_info; | |
146 monitor_info.cbSize = sizeof(monitor_info); | |
147 GetMonitorInfo(MonitorFromWindow(window_hwnd, MONITOR_DEFAULTTONEAREST), | |
148 &monitor_info); | |
149 return GetDisplay(monitor_info); | |
150 } | 273 } |
151 | 274 |
152 gfx::Display ScreenWin::GetDisplayNearestPoint(const gfx::Point& point) const { | 275 gfx::Display ScreenWin::GetDisplayNearestPoint(const gfx::Point& point) const { |
153 gfx::Point point_in_pixels = gfx::win::DIPToScreenPoint(point); | 276 return GetDisplayNearestScreenPoint(DIPToScreenPoint(point)).display(); |
154 POINT initial_loc = { point_in_pixels.x(), point_in_pixels.y() }; | |
155 HMONITOR monitor = MonitorFromPoint(initial_loc, MONITOR_DEFAULTTONEAREST); | |
156 MONITORINFOEX mi; | |
157 ZeroMemory(&mi, sizeof(MONITORINFOEX)); | |
158 mi.cbSize = sizeof(mi); | |
159 if (monitor && GetMonitorInfo(monitor, &mi)) { | |
160 return GetDisplay(mi); | |
161 } | |
162 return gfx::Display(); | |
163 } | 277 } |
164 | 278 |
165 gfx::Display ScreenWin::GetDisplayMatching(const gfx::Rect& match_rect) const { | 279 gfx::Display ScreenWin::GetDisplayMatching(const gfx::Rect& match_rect) const { |
166 RECT other_bounds_rect = match_rect.ToRECT(); | 280 return GetDisplayNearestScreenRect(match_rect).display(); |
167 MONITORINFOEX monitor_info = GetMonitorInfoForMonitor(MonitorFromRect( | |
168 &other_bounds_rect, MONITOR_DEFAULTTONEAREST)); | |
169 return GetDisplay(monitor_info); | |
170 } | 281 } |
171 | 282 |
172 gfx::Display ScreenWin::GetPrimaryDisplay() const { | 283 gfx::Display ScreenWin::GetPrimaryDisplay() const { |
173 MONITORINFOEX mi = GetMonitorInfoForMonitor( | 284 Display display = |
174 MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY)); | 285 GetDisplayWin(MonitorInfoFromHMONITOR(MonitorFromWindow( |
175 gfx::Display display = GetDisplay(mi); | 286 NULL, MONITOR_DEFAULTTOPRIMARY))).display(); |
176 // TODO(kevers|girard): Test if these checks can be reintroduced for high-DIP | 287 // TODO(kevers|girard): Test if these checks can be reintroduced for high-DIP |
177 // once more of the app is DIP-aware. | 288 // once more of the app is DIP-aware. |
178 if (GetDPIScale() == 1.0) { | 289 if (display.device_scale_factor() == 1.0) { |
179 DCHECK_EQ(GetSystemMetrics(SM_CXSCREEN), display.size().width()); | 290 DCHECK_EQ(GetSystemMetrics(SM_CXSCREEN), display.size().width()); |
180 DCHECK_EQ(GetSystemMetrics(SM_CYSCREEN), display.size().height()); | 291 DCHECK_EQ(GetSystemMetrics(SM_CYSCREEN), display.size().height()); |
181 } | 292 } |
182 return display; | 293 return display; |
183 } | 294 } |
184 | 295 |
185 void ScreenWin::AddObserver(DisplayObserver* observer) { | 296 void ScreenWin::AddObserver(DisplayObserver* observer) { |
186 change_notifier_.AddObserver(observer); | 297 change_notifier_.AddObserver(observer); |
187 } | 298 } |
188 | 299 |
189 void ScreenWin::RemoveObserver(DisplayObserver* observer) { | 300 void ScreenWin::RemoveObserver(DisplayObserver* observer) { |
190 change_notifier_.RemoveObserver(observer); | 301 change_notifier_.RemoveObserver(observer); |
191 } | 302 } |
192 | 303 |
| 304 gfx::Rect ScreenWin::ScreenToDIPRectInWindow( |
| 305 NativeView view, const gfx::Rect& screen_rect) const { |
| 306 HWND hwnd = view ? GetHWNDFromNativeView(view) : NULL; |
| 307 return ScreenWin::ScreenToDIPRect(hwnd, screen_rect); |
| 308 } |
| 309 |
| 310 gfx::Rect ScreenWin::DIPToScreenRectInWindow(NativeView view, |
| 311 const gfx::Rect& dip_rect) const { |
| 312 HWND hwnd = view ? GetHWNDFromNativeView(view) : NULL; |
| 313 return ScreenWin::DIPToScreenRect(hwnd, dip_rect); |
| 314 } |
| 315 |
| 316 ScreenWin::DisplayWin::DisplayWin() = default; |
| 317 |
| 318 ScreenWin::DisplayWin::DisplayWin(const DisplayInfo& display_info) |
| 319 : display_(display_info.id()), |
| 320 pixel_bounds_(display_info.screen_rect()) { |
| 321 float scale_factor = display_info.device_scale_factor(); |
| 322 display_.set_device_scale_factor(scale_factor); |
| 323 display_.set_work_area( |
| 324 gfx::ScaleToEnclosedRect(display_info.screen_work_rect(), |
| 325 1.0f / scale_factor)); |
| 326 display_.set_bounds(gfx::ScaleToEnclosedRect(display_info.screen_rect(), |
| 327 1.0f / scale_factor)); |
| 328 } |
| 329 |
| 330 ScreenWin::DisplayWin::DisplayWin(const DisplayWin& ref, |
| 331 const DisplayInfo& display_info) |
| 332 : display_(display_info.id()), |
| 333 pixel_bounds_(display_info.screen_rect()) { |
| 334 float scale_factor = display_info.device_scale_factor(); |
| 335 display_.set_device_scale_factor(scale_factor); |
| 336 const gfx::Insets pixel_insets = |
| 337 display_info.screen_rect().InsetsFrom(display_info.screen_work_rect()); |
| 338 const gfx::Insets scaled_insets = pixel_insets.Scale(1.0f / scale_factor, |
| 339 1.0f / scale_factor); |
| 340 const gfx::Rect scaled_bounds = |
| 341 gfx::win::ScaleAndPositionRect(ref.display_.bounds(), |
| 342 ref.physical_bounds(), |
| 343 display_info.screen_rect(), |
| 344 scale_factor); |
| 345 display_.set_bounds(scaled_bounds); |
| 346 gfx::Rect scaled_work_area(scaled_bounds); |
| 347 scaled_work_area.Inset(scaled_insets); |
| 348 display_.set_work_area(scaled_work_area); |
| 349 } |
| 350 |
| 351 // static |
| 352 ScreenWin::DisplayWin ScreenWin::GetDisplayNearestHWND(HWND hwnd) { |
| 353 ScreenWin* screen = GetNativeScreenWin(); |
| 354 return screen->GetDisplayWin(screen->MonitorInfoFromWindow(hwnd)); |
| 355 } |
| 356 |
| 357 // static |
| 358 ScreenWin::DisplayWin ScreenWin::GetDisplayNearestScreenRect( |
| 359 const Rect& screen_rect) { |
| 360 ScreenWin* screen = GetNativeScreenWin(); |
| 361 return screen->GetDisplayWin(screen->MonitorInfoFromScreenRect(screen_rect)); |
| 362 } |
| 363 |
| 364 // static |
| 365 ScreenWin::DisplayWin ScreenWin::GetDisplayNearestScreenPoint( |
| 366 const Point& screen_point) { |
| 367 ScreenWin* screen = GetNativeScreenWin(); |
| 368 return screen->GetDisplayWin( |
| 369 screen->MonitorInfoFromScreenPoint(screen_point)); |
| 370 } |
| 371 |
| 372 // static |
| 373 ScreenWin::DisplayWin ScreenWin::GetDisplayNearestDIPRect( |
| 374 const Rect& dip_rect) { |
| 375 ScreenWin* screen = GetNativeScreenWin(); |
| 376 DisplayWin closest_display_win; |
| 377 int64_t closest_distance_squared = INT64_MAX; |
| 378 for (const DisplayWin& display_win : screen->display_wins_) { |
| 379 Display display = display_win.display(); |
| 380 gfx::Rect dip_bounds = display.bounds(); |
| 381 int64_t distance_squared = |
| 382 gfx::win::SquaredDistanceBetweenRects(dip_rect, dip_bounds); |
| 383 if (distance_squared == 0) { |
| 384 return display_win; |
| 385 } else if (distance_squared < closest_distance_squared) { |
| 386 closest_distance_squared = distance_squared; |
| 387 closest_display_win = display_win; |
| 388 } |
| 389 } |
| 390 return closest_display_win; |
| 391 } |
| 392 |
| 393 // static |
| 394 ScreenWin::DisplayWin ScreenWin::GetDisplayNearestDIPPoint( |
| 395 const Point& dip_point) { |
| 396 ScreenWin* screen = GetNativeScreenWin(); |
| 397 DisplayWin primary_display_win; |
| 398 for (const DisplayWin& display_win : screen->display_wins_) { |
| 399 Display display = display_win.display(); |
| 400 gfx::Rect dip_bounds = display.bounds(); |
| 401 if (dip_bounds.Contains(dip_point)) |
| 402 return display_win; |
| 403 else if (dip_bounds.origin().IsOrigin()) |
| 404 primary_display_win = display_win; |
| 405 } |
| 406 return primary_display_win; |
| 407 } |
| 408 |
| 409 // static |
| 410 float ScreenWin::GetScaleFactorForHWND(HWND hwnd) { |
| 411 DCHECK(hwnd); |
| 412 ScreenWin* screen = GetNativeScreenWin(); |
| 413 HWND rootHwnd = screen->GetRootWindow(hwnd); |
| 414 return GetDisplayNearestHWND(rootHwnd).display().device_scale_factor(); |
| 415 } |
| 416 |
| 417 // static |
| 418 float ScreenWin::GetScaleFactorForScreenPoint(const Point& screen_point) { |
| 419 Display display = GetDisplayNearestScreenPoint(screen_point).display(); |
| 420 return display.device_scale_factor(); |
| 421 } |
| 422 |
| 423 // static |
| 424 std::vector<ScreenWin::DisplayInfo>::const_iterator |
| 425 ScreenWin::FindTouchingDisplayInfo( |
| 426 const DisplayWin& display_win, |
| 427 const std::vector<DisplayInfo>& display_infos) { |
| 428 auto end = display_infos.end(); |
| 429 for (auto display_info = display_infos.begin(); |
| 430 display_info != end; |
| 431 display_info++) { |
| 432 gfx::win::RectEdge edge = gfx::win::RectTouch(display_win.physical_bounds(), |
| 433 display_info->screen_rect()); |
| 434 if (edge != gfx::win::RectEdge::NONE) { |
| 435 return display_info; |
| 436 } |
| 437 } |
| 438 return end; |
| 439 } |
| 440 |
| 441 // static |
| 442 std::vector<ScreenWin::DisplayWin> ScreenWin::GetDisplaysFromDisplayInfos( |
| 443 const std::vector<ScreenWin::DisplayInfo>& display_infos) { |
| 444 std::vector<DisplayInfo> display_infos_remaining = display_infos; |
| 445 |
| 446 // Seed the primary display to layout all the other displays. |
| 447 std::vector<DisplayWin> display_wins; |
| 448 for (auto current = display_infos_remaining.begin(); |
| 449 current != display_infos_remaining.end(); |
| 450 current++) { |
| 451 if (current->screen_rect().origin().IsOrigin()) { |
| 452 display_wins.push_back(DisplayWin(*current)); |
| 453 display_infos_remaining.erase(current); |
| 454 break; |
| 455 } |
| 456 } |
| 457 |
| 458 // Scale touching display_infos relative to each other. |
| 459 size_t display_infos_at_cycle_start = 0; |
| 460 while ((display_infos_remaining.size() > 0) && |
| 461 (display_infos_remaining.size() != display_infos_at_cycle_start)) { |
| 462 display_infos_at_cycle_start = display_infos_remaining.size(); |
| 463 for (const DisplayWin& display_win : display_wins) { |
| 464 auto display_info = FindTouchingDisplayInfo(display_win, |
| 465 display_infos_remaining); |
| 466 if (display_info != display_infos_remaining.end()) { |
| 467 display_wins.push_back(DisplayWin(display_win, *display_info)); |
| 468 display_infos_remaining.erase(display_info); |
| 469 break; |
| 470 } |
| 471 } |
| 472 } |
| 473 |
| 474 // Under Windows DPI virtualization, not all display_infos touch, so scale |
| 475 // the remaining display infos relative to the origin. |
| 476 for (const DisplayInfo& display_info : display_infos_remaining) { |
| 477 display_wins.push_back(DisplayWin(display_info)); |
| 478 } |
| 479 |
| 480 return display_wins; |
| 481 } |
| 482 |
| 483 // static |
| 484 std::vector<ScreenWin::DisplayWin> ScreenWin::GetDisplayWins() { |
| 485 std::vector<DisplayInfo> display_infos; |
| 486 EnumDisplayMonitors(NULL, NULL, EnumMonitorCallback, |
| 487 reinterpret_cast<LPARAM>(&display_infos)); |
| 488 return GetDisplaysFromDisplayInfos(display_infos); |
| 489 } |
| 490 |
| 491 // static |
| 492 BOOL CALLBACK ScreenWin::EnumMonitorCallback(HMONITOR monitor, |
| 493 HDC hdc, |
| 494 LPRECT rect, |
| 495 LPARAM data) { |
| 496 std::vector<DisplayInfo>* display_infos = |
| 497 reinterpret_cast<std::vector<DisplayInfo>*>(data); |
| 498 DCHECK(display_infos); |
| 499 display_infos->push_back(DisplayInfo(monitor, gfx::GetDPIScale())); |
| 500 return TRUE; |
| 501 } |
| 502 |
193 void ScreenWin::OnWndProc(HWND hwnd, | 503 void ScreenWin::OnWndProc(HWND hwnd, |
194 UINT message, | 504 UINT message, |
195 WPARAM wparam, | 505 WPARAM wparam, |
196 LPARAM lparam) { | 506 LPARAM lparam) { |
197 if (message != WM_DISPLAYCHANGE) | 507 if (message != WM_DISPLAYCHANGE) |
198 return; | 508 return; |
199 | 509 |
200 std::vector<gfx::Display> old_displays = displays_; | 510 std::vector<gfx::Display> old_displays = GetAllDisplays(); |
201 displays_ = GetDisplays(); | 511 display_wins_ = GetDisplayWins(); |
| 512 std::vector<gfx::Display> new_displays = GetAllDisplays(); |
202 | 513 |
203 change_notifier_.NotifyDisplaysChanged(old_displays, displays_); | 514 change_notifier_.NotifyDisplaysChanged(old_displays, new_displays); |
204 } | 515 } |
205 | 516 |
206 // static | 517 MONITORINFOEX ScreenWin::MonitorInfoFromScreenPoint( |
207 std::vector<gfx::Display> ScreenWin::GetDisplaysForMonitorInfos( | 518 const gfx::Point& screen_point) const { |
208 const std::vector<MONITORINFOEX>& monitor_infos) { | 519 POINT initial_loc = { screen_point.x(), screen_point.y() }; |
209 std::vector<gfx::Display> displays; | 520 return MonitorInfoFromHMONITOR(::MonitorFromPoint(initial_loc, |
210 for (const MONITORINFOEX& monitor_info : monitor_infos) | 521 MONITOR_DEFAULTTONEAREST)); |
211 displays.push_back(GetDisplay(monitor_info)); | 522 } |
212 | 523 |
213 return displays; | 524 MONITORINFOEX ScreenWin::MonitorInfoFromScreenRect(const gfx::Rect& screen_rect) |
| 525 const { |
| 526 RECT win_rect = screen_rect.ToRECT(); |
| 527 return MonitorInfoFromHMONITOR(::MonitorFromRect(&win_rect, |
| 528 MONITOR_DEFAULTTONEAREST)); |
| 529 } |
| 530 |
| 531 MONITORINFOEX ScreenWin::MonitorInfoFromWindow(HWND hwnd) const { |
| 532 return MonitorInfoFromHMONITOR(::MonitorFromWindow(hwnd, |
| 533 MONITOR_DEFAULTTONEAREST)); |
| 534 } |
| 535 |
| 536 HWND ScreenWin::GetRootWindow(HWND hwnd) const { |
| 537 return GetAncestor(hwnd, GA_ROOT); |
| 538 } |
| 539 |
| 540 ScreenWin::DisplayWin ScreenWin::GetDisplayWin( |
| 541 const MONITORINFOEX& monitor_info) const { |
| 542 int64_t id = HashDeviceName(monitor_info.szDevice); |
| 543 for (const DisplayWin& display_win : display_wins_) { |
| 544 if (display_win.display().id() == id) |
| 545 return display_win; |
| 546 } |
| 547 NOTREACHED(); |
| 548 return DisplayWin(); |
214 } | 549 } |
215 | 550 |
216 } // namespace gfx | 551 } // namespace gfx |
OLD | NEW |