| Index: ui/gfx/screen_mac.mm
|
| diff --git a/ui/gfx/screen_mac.mm b/ui/gfx/screen_mac.mm
|
| index bbf29d335432be494224cbe8fbc1b0c9ce47d44a..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.
|
| @@ -78,7 +84,12 @@ gfx::Display GetDisplayForScreen(NSScreen* screen) {
|
|
|
| class ScreenMac : public gfx::Screen {
|
| public:
|
| - ScreenMac() {}
|
| + ScreenMac() {
|
| + displays_ = BuildDisplaysFromQuartz();
|
| +
|
| + CGDisplayRegisterReconfigurationCallback(
|
| + ScreenMac::DisplayReconfigurationCallBack, this);
|
| + }
|
|
|
| virtual bool IsDIPEnabled() OVERRIDE {
|
| return true;
|
| @@ -109,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(
|
| @@ -202,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>());
|
| + 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);
|
| };
|
|
|
|
|