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