Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / gfx / screen_mac.mm
index 377c859..8a1b0e0 100644 (file)
 
 #include "base/logging.h"
 #include "base/mac/sdk_forward_declarations.h"
+#include "base/timer/timer.h"
 #include "ui/gfx/display.h"
+#include "ui/gfx/display_change_notifier.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,18 +76,27 @@ 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;
+  virtual ~ScreenMac() {
+    CGDisplayRemoveReconfigurationCallback(
+        ScreenMac::DisplayReconfigurationCallBack, this);
   }
 
-  virtual gfx::Point GetCursorScreenPoint() OVERRIDE {
+  gfx::Point GetCursorScreenPoint() override {
     NSPoint mouseLocation  = [NSEvent mouseLocation];
     // Flip coordinates to gfx (0,0 in top-left corner) using primary screen.
     NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
@@ -87,23 +104,107 @@ class ScreenMac : public gfx::Screen {
     return gfx::Point(mouseLocation.x, mouseLocation.y);
   }
 
-  virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE {
+  gfx::NativeWindow GetWindowUnderCursor() override {
     NOTIMPLEMENTED();
     return gfx::NativeWindow();
   }
 
-  virtual gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point)
-      OVERRIDE {
+  gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) override {
     NOTIMPLEMENTED();
     return gfx::NativeWindow();
   }
 
-  virtual int GetNumDisplays() const OVERRIDE {
-    return GetAllDisplays().size();
+  int GetNumDisplays() const override { return GetAllDisplays().size(); }
+
+  std::vector<gfx::Display> GetAllDisplays() const override {
+    return displays_;
+  }
+
+  gfx::Display GetDisplayNearestWindow(gfx::NativeView view) const override {
+    NSWindow* window = nil;
+#if !defined(USE_AURA)
+    if (view)
+      window = [view window];
+#endif
+    if (!window)
+      return GetPrimaryDisplay();
+    NSScreen* match_screen = [window screen];
+    if (!match_screen)
+      return GetPrimaryDisplay();
+    return GetDisplayForScreen(match_screen);
+  }
+
+  gfx::Display GetDisplayNearestPoint(const gfx::Point& point) const override {
+    NSPoint ns_point = NSPointFromCGPoint(point.ToCGPoint());
+
+    NSArray* screens = [NSScreen screens];
+    NSScreen* primary = [screens objectAtIndex:0];
+    ns_point.y = NSMaxY([primary frame]) - ns_point.y;
+    for (NSScreen* screen in screens) {
+      if (NSMouseInRect(ns_point, [screen frame], NO))
+        return GetDisplayForScreen(screen);
+    }
+    return GetPrimaryDisplay();
+  }
+
+  // Returns the display that most closely intersects the provided bounds.
+  gfx::Display GetDisplayMatching(const gfx::Rect& match_rect) const override {
+    NSScreen* match_screen = GetMatchingScreen(match_rect);
+    return GetDisplayForScreen(match_screen);
+  }
+
+  // Returns the primary display.
+  gfx::Display GetPrimaryDisplay() const override {
+    // Primary display is defined as the display with the menubar,
+    // which is always at index 0.
+    NSScreen* primary = [[NSScreen screens] objectAtIndex:0];
+    gfx::Display display = GetDisplayForScreen(primary);
+    return display;
+  }
+
+  void AddObserver(gfx::DisplayObserver* observer) override {
+    change_notifier_.AddObserver(observer);
+  }
+
+  void RemoveObserver(gfx::DisplayObserver* observer) override {
+    change_notifier_.RemoveObserver(observer);
+  }
+
+  static void DisplayReconfigurationCallBack(CGDirectDisplayID display,
+                                             CGDisplayChangeSummaryFlags flags,
+                                             void* userInfo) {
+    if (flags & kCGDisplayBeginConfigurationFlag)
+      return;
 
+    static_cast<ScreenMac*>(userInfo)->HandleDisplayReconfiguration();
   }
 
-  virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE {
+  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();
+
+    change_notifier_.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
@@ -152,59 +253,15 @@ class ScreenMac : public gfx::Screen {
     return displays;
   }
 
-  virtual gfx::Display GetDisplayNearestWindow(
-      gfx::NativeView view) const OVERRIDE {
-    NSWindow* window = nil;
-#if !defined(USE_AURA)
-    window = [view window];
-#endif
-    if (!window)
-      return GetPrimaryDisplay();
-    NSScreen* match_screen = [window screen];
-    if (!match_screen)
-      return GetPrimaryDisplay();
-    return GetDisplayForScreen(match_screen);
-  }
-
-  virtual gfx::Display GetDisplayNearestPoint(
-      const gfx::Point& point) const OVERRIDE {
-    NSPoint ns_point = NSPointFromCGPoint(point.ToCGPoint());
-
-    NSArray* screens = [NSScreen screens];
-    NSScreen* primary = [screens objectAtIndex:0];
-    ns_point.y = NSMaxY([primary frame]) - ns_point.y;
-    for (NSScreen* screen in screens) {
-      if (NSMouseInRect(ns_point, [screen frame], NO))
-        return GetDisplayForScreen(screen);
-    }
-    return GetPrimaryDisplay();
-  }
-
-  // Returns the display that most closely intersects the provided bounds.
-  virtual gfx::Display GetDisplayMatching(
-      const gfx::Rect& match_rect) const OVERRIDE {
-    NSScreen* match_screen = GetMatchingScreen(match_rect);
-    return GetDisplayForScreen(match_screen);
-  }
+  // The displays currently attached to the device.
+  std::vector<gfx::Display> displays_;
 
-  // Returns the primary display.
-  virtual gfx::Display GetPrimaryDisplay() const OVERRIDE {
-    // Primary display is defined as the display with the menubar,
-    // which is always at index 0.
-    NSScreen* primary = [[NSScreen screens] objectAtIndex:0];
-    gfx::Display display = GetDisplayForScreen(primary);
-    return display;
-  }
+  // The timer to delay configuring outputs. See also the comments in
+  // HandleDisplayReconfiguration().
+  scoped_ptr<base::OneShotTimer<ScreenMac> > configure_timer_;
 
-  virtual void AddObserver(gfx::DisplayObserver* observer) OVERRIDE {
-    // TODO(oshima): crbug.com/122863.
-  }
+  gfx::DisplayChangeNotifier change_notifier_;
 
-  virtual void RemoveObserver(gfx::DisplayObserver* observer) OVERRIDE {
-    // TODO(oshima): crbug.com/122863.
-  }
-
- private:
   DISALLOW_COPY_AND_ASSIGN(ScreenMac);
 };