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.
5 #include "ui/gfx/screen_win.h"
10 #include "base/bind_helpers.h"
11 #include "base/hash.h"
12 #include "base/logging.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/win/win_util.h"
15 #include "ui/gfx/display.h"
16 #include "ui/gfx/win/dpi.h"
20 MONITORINFOEX
GetMonitorInfoForMonitor(HMONITOR monitor
) {
21 MONITORINFOEX monitor_info
;
22 ZeroMemory(&monitor_info
, sizeof(MONITORINFOEX
));
23 monitor_info
.cbSize
= sizeof(monitor_info
);
24 GetMonitorInfo(monitor
, &monitor_info
);
28 gfx::Display
GetDisplay(MONITORINFOEX
& monitor_info
) {
29 int64 id
= static_cast<int64
>(
30 base::Hash(base::WideToUTF8(monitor_info
.szDevice
)));
31 gfx::Rect bounds
= gfx::Rect(monitor_info
.rcMonitor
);
32 gfx::Display
display(id
, bounds
);
33 display
.set_work_area(gfx::Rect(monitor_info
.rcWork
));
34 display
.SetScaleAndBounds(gfx::GetDPIScale(), bounds
);
37 memset(&mode
, 0, sizeof(DEVMODE
));
38 mode
.dmSize
= sizeof(DEVMODE
);
39 mode
.dmDriverExtra
= 0;
40 if (EnumDisplaySettings(monitor_info
.szDevice
,
41 ENUM_CURRENT_SETTINGS
,
43 switch (mode
.dmDisplayOrientation
) {
45 display
.set_rotation(gfx::Display::ROTATE_0
);
48 display
.set_rotation(gfx::Display::ROTATE_90
);
51 display
.set_rotation(gfx::Display::ROTATE_180
);
54 display
.set_rotation(gfx::Display::ROTATE_270
);
64 BOOL CALLBACK
EnumMonitorCallback(HMONITOR monitor
,
68 std::vector
<gfx::Display
>* all_displays
=
69 reinterpret_cast<std::vector
<gfx::Display
>*>(data
);
72 MONITORINFOEX monitor_info
= GetMonitorInfoForMonitor(monitor
);
73 gfx::Display display
= GetDisplay(monitor_info
);
74 all_displays
->push_back(display
);
78 std::vector
<gfx::Display
> GetDisplays() {
79 std::vector
<gfx::Display
> displays
;
80 EnumDisplayMonitors(NULL
, NULL
, EnumMonitorCallback
,
81 reinterpret_cast<LPARAM
>(&displays
));
89 ScreenWin::ScreenWin()
90 : singleton_hwnd_observer_(new SingletonHwndObserver(
91 base::Bind(&ScreenWin::OnWndProc
, base::Unretained(this)))),
92 displays_(GetDisplays()) {
95 ScreenWin::~ScreenWin() {}
97 gfx::Point
ScreenWin::GetCursorScreenPoint() {
100 gfx::Point
cursor_pos_pixels(pt
);
101 return gfx::win::ScreenToDIPPoint(cursor_pos_pixels
);
104 gfx::NativeWindow
ScreenWin::GetWindowUnderCursor() {
106 HWND hwnd
= GetCursorPos(&cursor_loc
) ? WindowFromPoint(cursor_loc
) : NULL
;
107 return GetNativeWindowFromHWND(hwnd
);
110 gfx::NativeWindow
ScreenWin::GetWindowAtScreenPoint(const gfx::Point
& point
) {
111 gfx::Point point_in_pixels
= gfx::win::DIPToScreenPoint(point
);
112 return GetNativeWindowFromHWND(WindowFromPoint(point_in_pixels
.ToPOINT()));
115 int ScreenWin::GetNumDisplays() const {
116 return GetSystemMetrics(SM_CMONITORS
);
119 std::vector
<gfx::Display
> ScreenWin::GetAllDisplays() const {
123 gfx::Display
ScreenWin::GetDisplayNearestWindow(gfx::NativeView window
) const {
124 HWND window_hwnd
= GetHWNDFromNativeView(window
);
126 // When |window| isn't rooted to a display, we should just return the
127 // default display so we get some correct display information like the
129 return GetPrimaryDisplay();
132 MONITORINFOEX monitor_info
;
133 monitor_info
.cbSize
= sizeof(monitor_info
);
134 GetMonitorInfo(MonitorFromWindow(window_hwnd
, MONITOR_DEFAULTTONEAREST
),
136 return GetDisplay(monitor_info
);
139 gfx::Display
ScreenWin::GetDisplayNearestPoint(const gfx::Point
& point
) const {
140 gfx::Point point_in_pixels
= gfx::win::DIPToScreenPoint(point
);
141 POINT initial_loc
= { point_in_pixels
.x(), point_in_pixels
.y() };
142 HMONITOR monitor
= MonitorFromPoint(initial_loc
, MONITOR_DEFAULTTONEAREST
);
144 ZeroMemory(&mi
, sizeof(MONITORINFOEX
));
145 mi
.cbSize
= sizeof(mi
);
146 if (monitor
&& GetMonitorInfo(monitor
, &mi
)) {
147 return GetDisplay(mi
);
149 return gfx::Display();
152 gfx::Display
ScreenWin::GetDisplayMatching(const gfx::Rect
& match_rect
) const {
153 RECT other_bounds_rect
= match_rect
.ToRECT();
154 MONITORINFOEX monitor_info
= GetMonitorInfoForMonitor(MonitorFromRect(
155 &other_bounds_rect
, MONITOR_DEFAULTTONEAREST
));
156 return GetDisplay(monitor_info
);
159 gfx::Display
ScreenWin::GetPrimaryDisplay() const {
160 MONITORINFOEX mi
= GetMonitorInfoForMonitor(
161 MonitorFromWindow(NULL
, MONITOR_DEFAULTTOPRIMARY
));
162 gfx::Display display
= GetDisplay(mi
);
163 // TODO(kevers|girard): Test if these checks can be reintroduced for high-DIP
164 // once more of the app is DIP-aware.
165 if (GetDPIScale() == 1.0) {
166 DCHECK_EQ(GetSystemMetrics(SM_CXSCREEN
), display
.size().width());
167 DCHECK_EQ(GetSystemMetrics(SM_CYSCREEN
), display
.size().height());
172 void ScreenWin::AddObserver(DisplayObserver
* observer
) {
173 change_notifier_
.AddObserver(observer
);
176 void ScreenWin::RemoveObserver(DisplayObserver
* observer
) {
177 change_notifier_
.RemoveObserver(observer
);
180 void ScreenWin::OnWndProc(HWND hwnd
,
184 if (message
!= WM_DISPLAYCHANGE
)
187 std::vector
<gfx::Display
> old_displays
= displays_
;
188 displays_
= GetDisplays();
190 change_notifier_
.NotifyDisplaysChanged(old_displays
, displays_
);
193 HWND
ScreenWin::GetHWNDFromNativeView(NativeView window
) const {
198 NativeWindow
ScreenWin::GetNativeWindowFromHWND(HWND hwnd
) const {