Chromium Code Reviews| Index: ui/gfx/screen_mac.mm |
| diff --git a/ui/gfx/screen_mac.mm b/ui/gfx/screen_mac.mm |
| index 377c8592210b93f00da814c6383c2343d7c28fe7..09d3fccddb803ae32e51e583c29111d402815ace 100644 |
| --- a/ui/gfx/screen_mac.mm |
| +++ b/ui/gfx/screen_mac.mm |
| @@ -11,10 +11,16 @@ |
| #include "base/logging.h" |
| #include "base/mac/sdk_forward_declarations.h" |
| +#include "base/timer/timer.h" |
| #include "ui/gfx/display.h" |
| +#include "ui/gfx/screen_display_observer_delegate.h" |
| namespace { |
| +// The delay to handle the display configuration changes. |
| +// See comments in ScreenMac::HandleDisplayReconfiguration. |
| +const int64 kConfigureDelayMs = 500; |
| + |
| gfx::Rect ConvertCoordinateSystem(NSRect ns_rect) { |
| // Primary monitor is defined as the monitor with the menubar, |
| // which is always at index 0. |
| @@ -46,9 +52,11 @@ NSScreen* GetMatchingScreen(const gfx::Rect& match_rect) { |
| gfx::Display GetDisplayForScreen(NSScreen* screen) { |
| NSRect frame = [screen frame]; |
| - // TODO(oshima): Implement ID and Observer. |
| - gfx::Display display(0, gfx::Rect(NSRectToCGRect(frame))); |
| + CGDirectDisplayID display_id = [[[screen deviceDescription] |
| + objectForKey:@"NSScreenNumber"] unsignedIntValue]; |
| + |
| + gfx::Display display(display_id, gfx::Rect(NSRectToCGRect(frame))); |
| NSRect visible_frame = [screen visibleFrame]; |
| NSScreen* primary = [[NSScreen screens] objectAtIndex:0]; |
| @@ -68,12 +76,20 @@ gfx::Display GetDisplayForScreen(NSScreen* screen) { |
| else |
| scale = [screen userSpaceScaleFactor]; |
| display.set_device_scale_factor(scale); |
| + // CGDisplayRotation returns a double. Display::SetRotationAsDegree will |
| + // handle the unexpected situations were the angle is not a multiple of 90. |
| + display.SetRotationAsDegree(static_cast<int>(CGDisplayRotation(display_id))); |
| return display; |
| } |
| class ScreenMac : public gfx::Screen { |
| public: |
| - ScreenMac() {} |
| + ScreenMac() { |
| + displays_ = BuildDisplaysFromQuartz(); |
| + |
| + CGDisplayRegisterReconfigurationCallback( |
| + ScreenMac::DisplayReconfigurationCallBack, this); |
| + } |
| virtual bool IsDIPEnabled() OVERRIDE { |
| return true; |
| @@ -104,52 +120,7 @@ class ScreenMac : public gfx::Screen { |
| } |
| virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE { |
| - // Don't just return all online displays. This would include displays |
| - // that mirror other displays, which are not desired in this list. It's |
| - // tempting to use the count returned by CGGetActiveDisplayList, but active |
| - // displays exclude sleeping displays, and those are desired. |
| - |
| - // It would be ridiculous to have this many displays connected, but |
| - // CGDirectDisplayID is just an integer, so supporting up to this many |
| - // doesn't hurt. |
| - CGDirectDisplayID online_displays[128]; |
| - CGDisplayCount online_display_count = 0; |
| - if (CGGetOnlineDisplayList(arraysize(online_displays), |
| - online_displays, |
| - &online_display_count) != kCGErrorSuccess) { |
| - return std::vector<gfx::Display>(1, GetPrimaryDisplay()); |
| - } |
| - |
| - typedef std::map<int64, NSScreen*> ScreenIdsToScreensMap; |
| - ScreenIdsToScreensMap screen_ids_to_screens; |
| - for (NSScreen* screen in [NSScreen screens]) { |
| - NSDictionary* screen_device_description = [screen deviceDescription]; |
| - int64 screen_id = [[screen_device_description |
| - objectForKey:@"NSScreenNumber"] unsignedIntValue]; |
| - screen_ids_to_screens[screen_id] = screen; |
| - } |
| - |
| - std::vector<gfx::Display> displays; |
| - for (CGDisplayCount online_display_index = 0; |
| - online_display_index < online_display_count; |
| - ++online_display_index) { |
| - CGDirectDisplayID online_display = online_displays[online_display_index]; |
| - if (CGDisplayMirrorsDisplay(online_display) == kCGNullDirectDisplay) { |
| - // If this display doesn't mirror any other, include it in the list. |
| - // The primary display in a mirrored set will be counted, but those that |
| - // mirror it will not be. |
| - ScreenIdsToScreensMap::iterator foundScreen = |
| - screen_ids_to_screens.find(online_display); |
| - if (foundScreen != screen_ids_to_screens.end()) { |
| - displays.push_back(GetDisplayForScreen(foundScreen->second)); |
| - } |
| - } |
| - } |
| - |
| - if (!displays.size()) |
| - return std::vector<gfx::Display>(1, GetPrimaryDisplay()); |
| - |
| - return displays; |
| + return displays_; |
| } |
| virtual gfx::Display GetDisplayNearestWindow( |
| @@ -197,14 +168,105 @@ class ScreenMac : public gfx::Screen { |
| } |
| virtual void AddObserver(gfx::DisplayObserver* observer) OVERRIDE { |
| - // TODO(oshima): crbug.com/122863. |
| + observer_delegate_.AddObserver(observer); |
| } |
| virtual void RemoveObserver(gfx::DisplayObserver* observer) OVERRIDE { |
| - // TODO(oshima): crbug.com/122863. |
| + observer_delegate_.RemoveObserver(observer); |
| + } |
| + |
| + static void DisplayReconfigurationCallBack(CGDirectDisplayID display, |
| + CGDisplayChangeSummaryFlags flags, |
| + void* userInfo) { |
| + if (flags & kCGDisplayBeginConfigurationFlag) |
| + return; |
| + |
| + static_cast<ScreenMac*>(userInfo)->HandleDisplayReconfiguration(); |
| + } |
| + |
| + void HandleDisplayReconfiguration() { |
| + // Given that we need to rebuild the list of displays, we want to coalesce |
| + // the events. For that, we use a timer that will be reset every time we get |
| + // a new event and will be fulfilled kConfigureDelayMs after the latest. |
| + if (configure_timer_.get() && configure_timer_->IsRunning()) { |
| + configure_timer_->Reset(); |
| + return; |
| + } |
| + |
| + configure_timer_.reset(new base::OneShotTimer<ScreenMac>()); |
|
oshima
2014/07/09 17:12:51
Any reason not to use RepeatingTimer?
mlamouri (slow - plz ping)
2014/07/10 12:54:34
There is no repeating pattern here. The timer is o
|
| + configure_timer_->Start( |
| + FROM_HERE, |
| + base::TimeDelta::FromMilliseconds(kConfigureDelayMs), |
| + this, |
| + &ScreenMac::ConfigureTimerFired); |
| } |
| private: |
| + void ConfigureTimerFired() { |
| + std::vector<gfx::Display> old_displays = displays_; |
| + displays_ = BuildDisplaysFromQuartz(); |
| + |
| + observer_delegate_.NotifyDisplaysChanged(old_displays, displays_); |
| + } |
| + |
| + std::vector<gfx::Display> BuildDisplaysFromQuartz() const { |
| + // Don't just return all online displays. This would include displays |
| + // that mirror other displays, which are not desired in this list. It's |
| + // tempting to use the count returned by CGGetActiveDisplayList, but active |
| + // displays exclude sleeping displays, and those are desired. |
| + |
| + // It would be ridiculous to have this many displays connected, but |
| + // CGDirectDisplayID is just an integer, so supporting up to this many |
| + // doesn't hurt. |
| + CGDirectDisplayID online_displays[128]; |
| + CGDisplayCount online_display_count = 0; |
| + if (CGGetOnlineDisplayList(arraysize(online_displays), |
| + online_displays, |
| + &online_display_count) != kCGErrorSuccess) { |
| + return std::vector<gfx::Display>(1, GetPrimaryDisplay()); |
| + } |
| + |
| + typedef std::map<int64, NSScreen*> ScreenIdsToScreensMap; |
| + ScreenIdsToScreensMap screen_ids_to_screens; |
| + for (NSScreen* screen in [NSScreen screens]) { |
| + NSDictionary* screen_device_description = [screen deviceDescription]; |
| + int64 screen_id = [[screen_device_description |
| + objectForKey:@"NSScreenNumber"] unsignedIntValue]; |
| + screen_ids_to_screens[screen_id] = screen; |
| + } |
| + |
| + std::vector<gfx::Display> displays; |
| + for (CGDisplayCount online_display_index = 0; |
| + online_display_index < online_display_count; |
| + ++online_display_index) { |
| + CGDirectDisplayID online_display = online_displays[online_display_index]; |
| + if (CGDisplayMirrorsDisplay(online_display) == kCGNullDirectDisplay) { |
| + // If this display doesn't mirror any other, include it in the list. |
| + // The primary display in a mirrored set will be counted, but those that |
| + // mirror it will not be. |
| + ScreenIdsToScreensMap::iterator foundScreen = |
| + screen_ids_to_screens.find(online_display); |
| + if (foundScreen != screen_ids_to_screens.end()) { |
| + displays.push_back(GetDisplayForScreen(foundScreen->second)); |
| + } |
| + } |
| + } |
| + |
| + if (!displays.size()) |
| + return std::vector<gfx::Display>(1, GetPrimaryDisplay()); |
| + |
| + return displays; |
| + } |
| + |
| + // The displays currently attached to the device. |
| + std::vector<gfx::Display> displays_; |
| + |
| + // The timer to delay configuring outputs. See also the comments in |
| + // HandleDisplayReconfiguration(). |
| + scoped_ptr<base::OneShotTimer<ScreenMac> > configure_timer_; |
| + |
| + ScreenDisplayObserverDelegate observer_delegate_; |
| + |
| DISALLOW_COPY_AND_ASSIGN(ScreenMac); |
| }; |