| Index: ui/gfx/screen_win.cc
|
| diff --git a/ui/gfx/screen_win.cc b/ui/gfx/screen_win.cc
|
| index 3199f7acaacdd2b15c3dca37d09014dc418c2d00..53fbdb73f57027cdeff0240bcace46acf6aff8d9 100644
|
| --- a/ui/gfx/screen_win.cc
|
| +++ b/ui/gfx/screen_win.cc
|
| @@ -14,89 +14,179 @@
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "base/win/win_util.h"
|
| #include "ui/gfx/display.h"
|
| +#include "ui/gfx/geometry/insets.h"
|
| +#include "ui/gfx/geometry/point.h"
|
| +#include "ui/gfx/geometry/point_conversions.h"
|
| +#include "ui/gfx/geometry/rect.h"
|
| +#include "ui/gfx/geometry/safe_integer_conversions.h"
|
| +#include "ui/gfx/geometry/size.h"
|
| +#include "ui/gfx/geometry/vector2d.h"
|
| #include "ui/gfx/win/dpi.h"
|
| +#include "ui/gfx/win/rect_util.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(const MONITORINFOEX& monitor_info) {
|
| - int64_t id =
|
| - static_cast<int64_t>(base::Hash(base::WideToUTF8(monitor_info.szDevice)));
|
| - gfx::Rect bounds = gfx::Rect(monitor_info.rcMonitor);
|
| - gfx::Display display(id);
|
| - display.set_bounds(gfx::win::ScreenToDIPRect(bounds));
|
| - display.set_work_area(
|
| - gfx::win::ScreenToDIPRect(gfx::Rect(monitor_info.rcWork)));
|
| - display.SetScaleAndBounds(gfx::GetDPIScale(), bounds);
|
| -
|
| +gfx::Display::Rotation GetRotationForDevice(const wchar_t* device_name) {
|
| DEVMODE mode;
|
| - memset(&mode, 0, sizeof(DEVMODE));
|
| + ::ZeroMemory(&mode, sizeof(mode));
|
| mode.dmSize = sizeof(DEVMODE);
|
| mode.dmDriverExtra = 0;
|
| - if (EnumDisplaySettings(monitor_info.szDevice,
|
| - ENUM_CURRENT_SETTINGS,
|
| - &mode)) {
|
| + if (::EnumDisplaySettings(device_name, ENUM_CURRENT_SETTINGS, &mode)) {
|
| switch (mode.dmDisplayOrientation) {
|
| case DMDO_DEFAULT:
|
| - display.set_rotation(gfx::Display::ROTATE_0);
|
| - break;
|
| + return gfx::Display::ROTATE_0;
|
| case DMDO_90:
|
| - display.set_rotation(gfx::Display::ROTATE_90);
|
| - break;
|
| + return gfx::Display::ROTATE_90;
|
| case DMDO_180:
|
| - display.set_rotation(gfx::Display::ROTATE_180);
|
| - break;
|
| + return gfx::Display::ROTATE_180;
|
| case DMDO_270:
|
| - display.set_rotation(gfx::Display::ROTATE_270);
|
| - break;
|
| + return gfx::Display::ROTATE_270;
|
| default:
|
| NOTREACHED();
|
| }
|
| }
|
| -
|
| - return display;
|
| + return gfx::Display::ROTATE_0;
|
| }
|
|
|
| -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);
|
| +// Returns a point in |to_origin|'s coordinates and position scaled by
|
| +// |scale_factor|.
|
| +gfx::Point ScalePointRelative(const gfx::Point& from_origin,
|
| + const gfx::Point& to_origin,
|
| + const float scale_factor,
|
| + const gfx::Point& point) {
|
| + gfx::Vector2d from_origin_vector(from_origin.x(), from_origin.y());
|
| + gfx::Vector2d to_origin_vector(to_origin.x(), to_origin.y());
|
| + return gfx::ScaleToFlooredPoint(point - from_origin_vector, scale_factor) +
|
| + to_origin_vector;
|
| +}
|
|
|
| - MONITORINFOEX monitor_info = GetMonitorInfoForMonitor(monitor);
|
| - gfx::Display display = GetDisplay(monitor_info);
|
| - all_displays->push_back(display);
|
| - return TRUE;
|
| +// Returns the NativeScreen. For all intents and purposes, this screen provides
|
| +// the source of truth for displays in Windows.
|
| +gfx::ScreenWin* GetNativeScreenWin() {
|
| + return static_cast<gfx::ScreenWin*>(gfx::Screen::GetNativeScreen());
|
| }
|
|
|
| -std::vector<gfx::Display> GetDisplays() {
|
| - std::vector<gfx::Display> displays;
|
| - EnumDisplayMonitors(NULL, NULL, EnumMonitorCallback,
|
| - reinterpret_cast<LPARAM>(&displays));
|
| - return displays;
|
| +// static
|
| +MONITORINFOEX MonitorInfoFromHMONITOR(HMONITOR monitor) {
|
| + MONITORINFOEX monitor_info;
|
| + ::ZeroMemory(&monitor_info, sizeof(monitor_info));
|
| + monitor_info.cbSize = sizeof(monitor_info);
|
| + ::GetMonitorInfo(monitor, &monitor_info);
|
| + return monitor_info;
|
| }
|
|
|
| } // namespace
|
|
|
| namespace gfx {
|
|
|
| +class ScreenWin::DisplayWin {
|
| + public:
|
| + explicit DisplayWin();
|
| + explicit DisplayWin(const DisplayInfo& display_info);
|
| + DisplayWin(const DisplayWin& ref, const DisplayInfo& display_info);
|
| +
|
| + const Display& display() const { return display_; }
|
| + const Rect& physical_bounds() const { return pixel_bounds_; }
|
| +
|
| + private:
|
| + Display display_;
|
| + Rect pixel_bounds_;
|
| +};
|
| +
|
| ScreenWin::ScreenWin()
|
| : singleton_hwnd_observer_(new SingletonHwndObserver(
|
| base::Bind(&ScreenWin::OnWndProc, base::Unretained(this)))),
|
| - displays_(GetDisplays()) {
|
| -}
|
| + display_wins_(GetDisplayWins()) {}
|
|
|
| ScreenWin::~ScreenWin() {}
|
|
|
| +// static
|
| +Point ScreenWin::ScreenToDIPPoint(const Point& pixel_point) {
|
| + DisplayWin display_win = GetDisplayNearestScreenPoint(pixel_point);
|
| + Display display = display_win.display();
|
| + return ScalePointRelative(display_win.physical_bounds().origin(),
|
| + display.bounds().origin(),
|
| + 1.0f / display.device_scale_factor(),
|
| + pixel_point);
|
| +}
|
| +
|
| +// static
|
| +Point ScreenWin::DIPToScreenPoint(const Point& dip_point) {
|
| + DisplayWin display_win = GetDisplayNearestDIPPoint(dip_point);
|
| + Display display = display_win.display();
|
| + return ScalePointRelative(display.bounds().origin(),
|
| + display_win.physical_bounds().origin(),
|
| + display.device_scale_factor(),
|
| + dip_point);
|
| +}
|
| +
|
| +
|
| +Point ScreenWin::ClientToDIPPoint(HWND hwnd, const Point& client_point) {
|
| + return ScaleToFlooredPoint(client_point, 1.0f / GetScaleFactorForHWND(hwnd));
|
| +}
|
| +
|
| +Point ScreenWin::DIPToClientPoint(HWND hwnd, const Point& dip_point) {
|
| + return ScaleToFlooredPoint(dip_point, GetScaleFactorForHWND(hwnd));
|
| +}
|
| +
|
| +// static
|
| +Rect ScreenWin::ScreenToDIPRect(HWND hwnd, const Rect& pixel_bounds) {
|
| + // It's important we scale the origin and size separately. If we instead
|
| + // calculated the size from the floored origin and ceiled right the size could
|
| + // vary depending upon where the two points land. That would cause problems
|
| + // for the places this code is used (in particular mapping from native window
|
| + // bounds to DIPs).
|
| + if (hwnd) {
|
| + return Rect(ScreenToDIPPoint(pixel_bounds.origin()),
|
| + ScreenToDIPSize(hwnd, pixel_bounds.size()));
|
| + }
|
| + float scale_factor =
|
| + GetDisplayNearestScreenRect(pixel_bounds).display().device_scale_factor();
|
| + return Rect(ScreenToDIPPoint(pixel_bounds.origin()),
|
| + ScaleToCeiledSize(pixel_bounds.size(), 1.0f / scale_factor));
|
| +}
|
| +
|
| +// static
|
| +Rect ScreenWin::DIPToScreenRect(HWND hwnd, const Rect& dip_bounds) {
|
| + // See comment in ScreenToDIPRect for why we calculate size like this.
|
| + if (hwnd) {
|
| + return Rect(DIPToScreenPoint(dip_bounds.origin()),
|
| + DIPToScreenSize(hwnd, dip_bounds.size()));
|
| + }
|
| + // Because origins don't change for screen points and scaling factors are
|
| + // greater than 1, the monitor bounding rect always contains the DIP point.
|
| + float scale_factor =
|
| + GetDisplayNearestDIPRect(dip_bounds).display().device_scale_factor();
|
| + return Rect(DIPToScreenPoint(dip_bounds.origin()),
|
| + ScaleToCeiledSize(dip_bounds.size(), scale_factor));
|
| +}
|
| +
|
| +// static
|
| +Rect ScreenWin::ClientToDIPRect(HWND hwnd, const Rect& pixel_bounds) {
|
| + // See comment in ScreenToDIPRect for why we calculate size like this.
|
| + return Rect(ClientToDIPPoint(hwnd, pixel_bounds.origin()),
|
| + ScreenToDIPSize(hwnd, pixel_bounds.size()));
|
| +}
|
| +
|
| +// static
|
| +Rect ScreenWin::DIPToClientRect(HWND hwnd, const Rect& dip_bounds) {
|
| + // See comment in ScreenToDIPRect for why we calculate size like this.
|
| + return Rect(DIPToClientPoint(hwnd, dip_bounds.origin()),
|
| + DIPToScreenSize(hwnd, dip_bounds.size()));
|
| +}
|
| +
|
| +// static
|
| +Size ScreenWin::ScreenToDIPSize(HWND hwnd, const Size& size_in_pixels) {
|
| + // Always ceil sizes. Otherwise we may be leaving off part of the bounds.
|
| + return ScaleToCeiledSize(size_in_pixels, 1.0f / GetScaleFactorForHWND(hwnd));
|
| +}
|
| +
|
| +// static
|
| +Size ScreenWin::DIPToScreenSize(HWND hwnd, const Size& dip_size) {
|
| + // Always ceil sizes. Otherwise we may be leaving off part of the bounds.
|
| + return ScaleToCeiledSize(dip_size, GetScaleFactorForHWND(hwnd));
|
| +}
|
| +
|
| HWND ScreenWin::GetHWNDFromNativeView(NativeView window) const {
|
| NOTREACHED();
|
| return NULL;
|
| @@ -107,11 +197,45 @@ NativeWindow ScreenWin::GetNativeWindowFromHWND(HWND hwnd) const {
|
| return NULL;
|
| }
|
|
|
| +ScreenWin::DisplayInfo::DisplayInfo(HMONITOR monitor,
|
| + float device_scale_factor) :
|
| + device_scale_factor_(device_scale_factor){
|
| + MONITORINFOEX monitor_info;
|
| + ::ZeroMemory(&monitor_info, sizeof(monitor_info));
|
| + monitor_info.cbSize = sizeof(monitor_info);
|
| + ::GetMonitorInfo(monitor, &monitor_info);
|
| + InitializeFromMonitorInfo(monitor_info);
|
| +}
|
| +
|
| +ScreenWin::DisplayInfo::DisplayInfo(const MONITORINFOEX& monitor_info,
|
| + gfx::Display::Rotation rotation,
|
| + float device_scale_factor)
|
| + : rotation_(rotation),
|
| + device_scale_factor_(device_scale_factor) {
|
| + InitializeFromMonitorInfo(monitor_info);
|
| +}
|
| +
|
| +void ScreenWin::DisplayInfo::InitializeFromMonitorInfo(
|
| + const MONITORINFOEX& monitor_info) {
|
| + id_ = ScreenWin::HashDeviceName(monitor_info.szDevice);
|
| + screen_rect_ = gfx::Rect(monitor_info.rcMonitor);
|
| + screen_work_rect_ = gfx::Rect(monitor_info.rcWork);
|
| + rotation_ = GetRotationForDevice(monitor_info.szDevice);
|
| +}
|
| +
|
| +ScreenWin::ScreenWin(const std::vector<ScreenWin::DisplayInfo>& display_infos) {
|
| + display_wins_ = GetDisplaysFromDisplayInfos(display_infos);
|
| +}
|
| +
|
| +int64_t ScreenWin::HashDeviceName(const wchar_t* device_name) {
|
| + return static_cast<int64_t>(base::Hash(base::WideToUTF8(device_name)));
|
| +}
|
| +
|
| gfx::Point ScreenWin::GetCursorScreenPoint() {
|
| POINT pt;
|
| GetCursorPos(&pt);
|
| gfx::Point cursor_pos_pixels(pt);
|
| - return gfx::win::ScreenToDIPPoint(cursor_pos_pixels);
|
| + return ScreenToDIPPoint(cursor_pos_pixels);
|
| }
|
|
|
| gfx::NativeWindow ScreenWin::GetWindowUnderCursor() {
|
| @@ -121,7 +245,7 @@ gfx::NativeWindow ScreenWin::GetWindowUnderCursor() {
|
| }
|
|
|
| gfx::NativeWindow ScreenWin::GetWindowAtScreenPoint(const gfx::Point& point) {
|
| - gfx::Point point_in_pixels = gfx::win::DIPToScreenPoint(point);
|
| + gfx::Point point_in_pixels = DIPToScreenPoint(point);
|
| return GetNativeWindowFromHWND(WindowFromPoint(point_in_pixels.ToPOINT()));
|
| }
|
|
|
| @@ -130,7 +254,11 @@ int ScreenWin::GetNumDisplays() const {
|
| }
|
|
|
| std::vector<gfx::Display> ScreenWin::GetAllDisplays() const {
|
| - return displays_;
|
| + std::vector<gfx::Display> displays;
|
| + for (const DisplayWin& display_win : display_wins_) {
|
| + displays.push_back(display_win.display());
|
| + }
|
| + return displays;
|
| }
|
|
|
| gfx::Display ScreenWin::GetDisplayNearestWindow(gfx::NativeView window) const {
|
| @@ -141,41 +269,24 @@ gfx::Display ScreenWin::GetDisplayNearestWindow(gfx::NativeView window) const {
|
| // 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);
|
| + return GetDisplayNearestHWND(window_hwnd).display();
|
| }
|
|
|
| gfx::Display ScreenWin::GetDisplayNearestPoint(const gfx::Point& point) const {
|
| - gfx::Point point_in_pixels = gfx::win::DIPToScreenPoint(point);
|
| - POINT initial_loc = { point_in_pixels.x(), point_in_pixels.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();
|
| + return GetDisplayNearestScreenPoint(DIPToScreenPoint(point)).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);
|
| + return GetDisplayNearestScreenRect(match_rect).display();
|
| }
|
|
|
| gfx::Display ScreenWin::GetPrimaryDisplay() const {
|
| - MONITORINFOEX mi = GetMonitorInfoForMonitor(
|
| - MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY));
|
| - gfx::Display display = GetDisplay(mi);
|
| + Display display =
|
| + GetDisplayWin(MonitorInfoFromHMONITOR(MonitorFromWindow(
|
| + NULL, MONITOR_DEFAULTTOPRIMARY))).display();
|
| // TODO(kevers|girard): Test if these checks can be reintroduced for high-DIP
|
| // once more of the app is DIP-aware.
|
| - if (GetDPIScale() == 1.0) {
|
| + if (display.device_scale_factor() == 1.0) {
|
| DCHECK_EQ(GetSystemMetrics(SM_CXSCREEN), display.size().width());
|
| DCHECK_EQ(GetSystemMetrics(SM_CYSCREEN), display.size().height());
|
| }
|
| @@ -190,6 +301,205 @@ void ScreenWin::RemoveObserver(DisplayObserver* observer) {
|
| change_notifier_.RemoveObserver(observer);
|
| }
|
|
|
| +gfx::Rect ScreenWin::ScreenToDIPRectInWindow(
|
| + NativeView view, const gfx::Rect& screen_rect) const {
|
| + HWND hwnd = view ? GetHWNDFromNativeView(view) : NULL;
|
| + return ScreenWin::ScreenToDIPRect(hwnd, screen_rect);
|
| +}
|
| +
|
| +gfx::Rect ScreenWin::DIPToScreenRectInWindow(NativeView view,
|
| + const gfx::Rect& dip_rect) const {
|
| + HWND hwnd = view ? GetHWNDFromNativeView(view) : NULL;
|
| + return ScreenWin::DIPToScreenRect(hwnd, dip_rect);
|
| +}
|
| +
|
| +ScreenWin::DisplayWin::DisplayWin() = default;
|
| +
|
| +ScreenWin::DisplayWin::DisplayWin(const DisplayInfo& display_info)
|
| + : display_(display_info.id()),
|
| + pixel_bounds_(display_info.screen_rect()) {
|
| + float scale_factor = display_info.device_scale_factor();
|
| + display_.set_device_scale_factor(scale_factor);
|
| + display_.set_work_area(
|
| + gfx::ScaleToEnclosedRect(display_info.screen_work_rect(),
|
| + 1.0f / scale_factor));
|
| + display_.set_bounds(gfx::ScaleToEnclosedRect(display_info.screen_rect(),
|
| + 1.0f / scale_factor));
|
| +}
|
| +
|
| +ScreenWin::DisplayWin::DisplayWin(const DisplayWin& ref,
|
| + const DisplayInfo& display_info)
|
| + : display_(display_info.id()),
|
| + pixel_bounds_(display_info.screen_rect()) {
|
| + float scale_factor = display_info.device_scale_factor();
|
| + display_.set_device_scale_factor(scale_factor);
|
| + const gfx::Insets pixel_insets =
|
| + display_info.screen_rect().InsetsFrom(display_info.screen_work_rect());
|
| + const gfx::Insets scaled_insets = pixel_insets.Scale(1.0f / scale_factor,
|
| + 1.0f / scale_factor);
|
| + const gfx::Rect scaled_bounds =
|
| + gfx::win::ScaleAndPositionRect(ref.display_.bounds(),
|
| + ref.physical_bounds(),
|
| + display_info.screen_rect(),
|
| + scale_factor);
|
| + display_.set_bounds(scaled_bounds);
|
| + gfx::Rect scaled_work_area(scaled_bounds);
|
| + scaled_work_area.Inset(scaled_insets);
|
| + display_.set_work_area(scaled_work_area);
|
| +}
|
| +
|
| +// static
|
| +ScreenWin::DisplayWin ScreenWin::GetDisplayNearestHWND(HWND hwnd) {
|
| + ScreenWin* screen = GetNativeScreenWin();
|
| + return screen->GetDisplayWin(screen->MonitorInfoFromWindow(hwnd));
|
| +}
|
| +
|
| +// static
|
| +ScreenWin::DisplayWin ScreenWin::GetDisplayNearestScreenRect(
|
| + const Rect& screen_rect) {
|
| + ScreenWin* screen = GetNativeScreenWin();
|
| + return screen->GetDisplayWin(screen->MonitorInfoFromScreenRect(screen_rect));
|
| +}
|
| +
|
| +// static
|
| +ScreenWin::DisplayWin ScreenWin::GetDisplayNearestScreenPoint(
|
| + const Point& screen_point) {
|
| + ScreenWin* screen = GetNativeScreenWin();
|
| + return screen->GetDisplayWin(
|
| + screen->MonitorInfoFromScreenPoint(screen_point));
|
| +}
|
| +
|
| +// static
|
| +ScreenWin::DisplayWin ScreenWin::GetDisplayNearestDIPRect(
|
| + const Rect& dip_rect) {
|
| + ScreenWin* screen = GetNativeScreenWin();
|
| + DisplayWin closest_display_win;
|
| + int64_t closest_distance_squared = INT64_MAX;
|
| + for (const DisplayWin& display_win : screen->display_wins_) {
|
| + Display display = display_win.display();
|
| + gfx::Rect dip_bounds = display.bounds();
|
| + int64_t distance_squared =
|
| + gfx::win::SquaredDistanceBetweenRects(dip_rect, dip_bounds);
|
| + if (distance_squared == 0) {
|
| + return display_win;
|
| + } else if (distance_squared < closest_distance_squared) {
|
| + closest_distance_squared = distance_squared;
|
| + closest_display_win = display_win;
|
| + }
|
| + }
|
| + return closest_display_win;
|
| +}
|
| +
|
| +// static
|
| +ScreenWin::DisplayWin ScreenWin::GetDisplayNearestDIPPoint(
|
| + const Point& dip_point) {
|
| + ScreenWin* screen = GetNativeScreenWin();
|
| + DisplayWin primary_display_win;
|
| + for (const DisplayWin& display_win : screen->display_wins_) {
|
| + Display display = display_win.display();
|
| + gfx::Rect dip_bounds = display.bounds();
|
| + if (dip_bounds.Contains(dip_point))
|
| + return display_win;
|
| + else if (dip_bounds.origin().IsOrigin())
|
| + primary_display_win = display_win;
|
| + }
|
| + return primary_display_win;
|
| +}
|
| +
|
| +// static
|
| +float ScreenWin::GetScaleFactorForHWND(HWND hwnd) {
|
| + DCHECK(hwnd);
|
| + ScreenWin* screen = GetNativeScreenWin();
|
| + HWND rootHwnd = screen->GetRootWindow(hwnd);
|
| + return GetDisplayNearestHWND(rootHwnd).display().device_scale_factor();
|
| +}
|
| +
|
| +// static
|
| +float ScreenWin::GetScaleFactorForScreenPoint(const Point& screen_point) {
|
| + Display display = GetDisplayNearestScreenPoint(screen_point).display();
|
| + return display.device_scale_factor();
|
| +}
|
| +
|
| +// static
|
| +std::vector<ScreenWin::DisplayInfo>::const_iterator
|
| +ScreenWin::FindTouchingDisplayInfo(
|
| + const DisplayWin& display_win,
|
| + const std::vector<DisplayInfo>& display_infos) {
|
| + auto end = display_infos.end();
|
| + for (auto display_info = display_infos.begin();
|
| + display_info != end;
|
| + display_info++) {
|
| + gfx::win::RectEdge edge = gfx::win::RectTouch(display_win.physical_bounds(),
|
| + display_info->screen_rect());
|
| + if (edge != gfx::win::RectEdge::NONE) {
|
| + return display_info;
|
| + }
|
| + }
|
| + return end;
|
| +}
|
| +
|
| +// static
|
| +std::vector<ScreenWin::DisplayWin> ScreenWin::GetDisplaysFromDisplayInfos(
|
| + const std::vector<ScreenWin::DisplayInfo>& display_infos) {
|
| + std::vector<DisplayInfo> display_infos_remaining = display_infos;
|
| +
|
| + // Seed the primary display to layout all the other displays.
|
| + std::vector<DisplayWin> display_wins;
|
| + for (auto current = display_infos_remaining.begin();
|
| + current != display_infos_remaining.end();
|
| + current++) {
|
| + if (current->screen_rect().origin().IsOrigin()) {
|
| + display_wins.push_back(DisplayWin(*current));
|
| + display_infos_remaining.erase(current);
|
| + break;
|
| + }
|
| + }
|
| +
|
| + // Scale touching display_infos relative to each other.
|
| + size_t display_infos_at_cycle_start = 0;
|
| + while ((display_infos_remaining.size() > 0) &&
|
| + (display_infos_remaining.size() != display_infos_at_cycle_start)) {
|
| + display_infos_at_cycle_start = display_infos_remaining.size();
|
| + for (const DisplayWin& display_win : display_wins) {
|
| + auto display_info = FindTouchingDisplayInfo(display_win,
|
| + display_infos_remaining);
|
| + if (display_info != display_infos_remaining.end()) {
|
| + display_wins.push_back(DisplayWin(display_win, *display_info));
|
| + display_infos_remaining.erase(display_info);
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Under Windows DPI virtualization, not all display_infos touch, so scale
|
| + // the remaining display infos relative to the origin.
|
| + for (const DisplayInfo& display_info : display_infos_remaining) {
|
| + display_wins.push_back(DisplayWin(display_info));
|
| + }
|
| +
|
| + return display_wins;
|
| +}
|
| +
|
| +// static
|
| +std::vector<ScreenWin::DisplayWin> ScreenWin::GetDisplayWins() {
|
| + std::vector<DisplayInfo> display_infos;
|
| + EnumDisplayMonitors(NULL, NULL, EnumMonitorCallback,
|
| + reinterpret_cast<LPARAM>(&display_infos));
|
| + return GetDisplaysFromDisplayInfos(display_infos);
|
| +}
|
| +
|
| +// static
|
| +BOOL CALLBACK ScreenWin::EnumMonitorCallback(HMONITOR monitor,
|
| + HDC hdc,
|
| + LPRECT rect,
|
| + LPARAM data) {
|
| + std::vector<DisplayInfo>* display_infos =
|
| + reinterpret_cast<std::vector<DisplayInfo>*>(data);
|
| + DCHECK(display_infos);
|
| + display_infos->push_back(DisplayInfo(monitor, gfx::GetDPIScale()));
|
| + return TRUE;
|
| +}
|
| +
|
| void ScreenWin::OnWndProc(HWND hwnd,
|
| UINT message,
|
| WPARAM wparam,
|
| @@ -197,20 +507,45 @@ void ScreenWin::OnWndProc(HWND hwnd,
|
| if (message != WM_DISPLAYCHANGE)
|
| return;
|
|
|
| - std::vector<gfx::Display> old_displays = displays_;
|
| - displays_ = GetDisplays();
|
| + std::vector<gfx::Display> old_displays = GetAllDisplays();
|
| + display_wins_ = GetDisplayWins();
|
| + std::vector<gfx::Display> new_displays = GetAllDisplays();
|
|
|
| - change_notifier_.NotifyDisplaysChanged(old_displays, displays_);
|
| + change_notifier_.NotifyDisplaysChanged(old_displays, new_displays);
|
| }
|
|
|
| -// static
|
| -std::vector<gfx::Display> ScreenWin::GetDisplaysForMonitorInfos(
|
| - const std::vector<MONITORINFOEX>& monitor_infos) {
|
| - std::vector<gfx::Display> displays;
|
| - for (const MONITORINFOEX& monitor_info : monitor_infos)
|
| - displays.push_back(GetDisplay(monitor_info));
|
| +MONITORINFOEX ScreenWin::MonitorInfoFromScreenPoint(
|
| + const gfx::Point& screen_point) const {
|
| + POINT initial_loc = { screen_point.x(), screen_point.y() };
|
| + return MonitorInfoFromHMONITOR(::MonitorFromPoint(initial_loc,
|
| + MONITOR_DEFAULTTONEAREST));
|
| +}
|
|
|
| - return displays;
|
| +MONITORINFOEX ScreenWin::MonitorInfoFromScreenRect(const gfx::Rect& screen_rect)
|
| + const {
|
| + RECT win_rect = screen_rect.ToRECT();
|
| + return MonitorInfoFromHMONITOR(::MonitorFromRect(&win_rect,
|
| + MONITOR_DEFAULTTONEAREST));
|
| +}
|
| +
|
| +MONITORINFOEX ScreenWin::MonitorInfoFromWindow(HWND hwnd) const {
|
| + return MonitorInfoFromHMONITOR(::MonitorFromWindow(hwnd,
|
| + MONITOR_DEFAULTTONEAREST));
|
| +}
|
| +
|
| +HWND ScreenWin::GetRootWindow(HWND hwnd) const {
|
| + return GetAncestor(hwnd, GA_ROOT);
|
| +}
|
| +
|
| +ScreenWin::DisplayWin ScreenWin::GetDisplayWin(
|
| + const MONITORINFOEX& monitor_info) const {
|
| + int64_t id = HashDeviceName(monitor_info.szDevice);
|
| + for (const DisplayWin& display_win : display_wins_) {
|
| + if (display_win.display().id() == id)
|
| + return display_win;
|
| + }
|
| + NOTREACHED();
|
| + return DisplayWin();
|
| }
|
|
|
| } // namespace gfx
|
|
|