Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(160)

Unified Diff: ui/display/mac/screen_mac.mm

Issue 2514703002: Mac: Use a cache for ScreenMac::GetDisplayForScreen(). (Closed)
Patch Set: Early exit Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/display/mac/screen_mac.mm
diff --git a/ui/display/mac/screen_mac.mm b/ui/display/mac/screen_mac.mm
index 366662805fe4fc80a777fe9dc272278068326cb6..e18be321034aa0ba4729dc761be46d702ad8c2ce 100644
--- a/ui/display/mac/screen_mac.mm
+++ b/ui/display/mac/screen_mac.mm
@@ -50,7 +50,7 @@ NSScreen* GetMatchingScreen(const gfx::Rect& match_rect) {
return max_screen;
}
-Display GetDisplayForScreen(NSScreen* screen) {
+Display BuildDisplayForScreen(NSScreen* screen) {
NSRect frame = [screen frame];
CGDirectDisplayID display_id = [[[screen deviceDescription]
@@ -95,6 +95,10 @@ Display GetDisplayForScreen(NSScreen* screen) {
return display;
}
+Display BuildPrimaryDisplay() {
+ return BuildDisplayForScreen([[NSScreen screens] firstObject]);
+}
+
// Returns the minimum Manhattan distance from |point| to corners of |screen|
// frame.
CGFloat GetMinimumDistanceToCorner(const NSPoint& point, NSScreen* screen) {
@@ -112,9 +116,13 @@ CGFloat GetMinimumDistanceToCorner(const NSPoint& point, NSScreen* screen) {
class ScreenMac : public Screen {
public:
- ScreenMac() {
- displays_ = BuildDisplaysFromQuartz();
-
+ ScreenMac()
+ : configure_timer_(
+ FROM_HERE,
+ base::TimeDelta::FromMilliseconds(kConfigureDelayMs),
+ base::Bind(&ScreenMac::ConfigureTimerFired, base::Unretained(this)),
+ false) {
+ old_displays_ = displays_ = BuildDisplaysFromQuartz();
CGDisplayRegisterReconfigurationCallback(
ScreenMac::DisplayReconfigurationCallBack, this);
}
@@ -146,6 +154,10 @@ class ScreenMac : public Screen {
}
Display GetDisplayNearestWindow(gfx::NativeView view) const override {
+ EnsureDisplaysValid();
+ if (displays_.size() == 1)
+ return displays_[0];
+
NSWindow* window = nil;
#if !defined(USE_AURA)
if (view)
@@ -153,10 +165,15 @@ class ScreenMac : public Screen {
#endif
if (!window)
return GetPrimaryDisplay();
+
+ // Note the following line calls -[NSWindow
+ // _bestScreenBySpaceAssignmentOrGeometry] which is quite expensive and
+ // performs IPC with the window server process.
NSScreen* match_screen = [window screen];
+
if (!match_screen)
return GetPrimaryDisplay();
- return GetDisplayForScreen(match_screen);
+ return GetCachedDisplayForScreen(match_screen);
}
Display GetDisplayNearestPoint(const gfx::Point& point) const override {
@@ -169,7 +186,7 @@ class ScreenMac : public Screen {
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 GetCachedDisplayForScreen(screen);
}
NSScreen* nearest_screen = primary;
@@ -181,13 +198,13 @@ class ScreenMac : public Screen {
nearest_screen = screen;
}
}
- return GetDisplayForScreen(nearest_screen);
+ return GetCachedDisplayForScreen(nearest_screen);
}
// Returns the display that most closely intersects the provided bounds.
Display GetDisplayMatching(const gfx::Rect& match_rect) const override {
NSScreen* match_screen = GetMatchingScreen(match_rect);
- return GetDisplayForScreen(match_screen);
+ return GetCachedDisplayForScreen(match_screen);
}
// Returns the primary display.
@@ -195,7 +212,7 @@ class ScreenMac : public Screen {
// Primary display is defined as the display with the menubar,
// which is always at index 0.
NSScreen* primary = [[NSScreen screens] firstObject];
- Display display = GetDisplayForScreen(primary);
+ Display display = GetCachedDisplayForScreen(primary);
return display;
}
@@ -213,30 +230,38 @@ class ScreenMac : public Screen {
if (flags & kCGDisplayBeginConfigurationFlag)
return;
- static_cast<ScreenMac*>(userInfo)->HandleDisplayReconfiguration();
+ ScreenMac* screen_mac = static_cast<ScreenMac*>(userInfo);
+
+ // Timer::Reset() ensures at least another interval passes before the
+ // associated task runs, effectively coalescing these events.
+ screen_mac->configure_timer_.Reset();
+ screen_mac->displays_require_update_ = true;
}
- 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;
+ private:
+ Display GetCachedDisplayForScreen(NSScreen* screen) const {
+ EnsureDisplaysValid();
+ const CGDirectDisplayID display_id = [[[screen deviceDescription]
+ objectForKey:@"NSScreenNumber"] unsignedIntValue];
+ for (const Display& display : displays_) {
+ if (display_id == display.id())
+ return display;
}
+ NOTREACHED(); // Asked for a hidden/sleeping/mirrored screen?
+ return BuildDisplayForScreen(screen);
+ }
- configure_timer_.reset(new base::OneShotTimer());
- configure_timer_->Start(
- FROM_HERE, base::TimeDelta::FromMilliseconds(kConfigureDelayMs), this,
- &ScreenMac::ConfigureTimerFired);
+ void EnsureDisplaysValid() const {
+ if (displays_require_update_) {
+ displays_ = BuildDisplaysFromQuartz();
+ displays_require_update_ = false;
+ }
}
- private:
void ConfigureTimerFired() {
- std::vector<Display> old_displays = displays_;
- displays_ = BuildDisplaysFromQuartz();
-
- change_notifier_.NotifyDisplaysChanged(old_displays, displays_);
+ EnsureDisplaysValid();
+ change_notifier_.NotifyDisplaysChanged(old_displays_, displays_);
+ old_displays_ = displays_;
}
std::vector<Display> BuildDisplaysFromQuartz() const {
@@ -252,7 +277,7 @@ class ScreenMac : public Screen {
CGDisplayCount online_display_count = 0;
if (CGGetOnlineDisplayList(arraysize(online_displays), online_displays,
&online_display_count) != kCGErrorSuccess) {
- return std::vector<Display>(1, GetPrimaryDisplay());
+ return std::vector<Display>(1, BuildPrimaryDisplay());
}
typedef std::map<int64_t, NSScreen*> ScreenIdsToScreensMap;
@@ -275,21 +300,27 @@ class ScreenMac : public Screen {
ScreenIdsToScreensMap::iterator foundScreen =
screen_ids_to_screens.find(online_display);
if (foundScreen != screen_ids_to_screens.end()) {
- displays.push_back(GetDisplayForScreen(foundScreen->second));
+ displays.push_back(BuildDisplayForScreen(foundScreen->second));
}
}
}
- return displays.empty() ? std::vector<Display>(1, GetPrimaryDisplay())
+ return displays.empty() ? std::vector<Display>(1, BuildPrimaryDisplay())
: displays;
}
- // The displays currently attached to the device.
- std::vector<Display> displays_;
+ // The displays currently attached to the device. Cached.
+ mutable std::vector<Display> displays_;
+
+ // Set whenever the CGDisplayRegisterReconfigurationCallback is invoked and
+ // cleared when |displays_| is updated by BuildDisplaysFromQuartz().
+ mutable bool displays_require_update_ = false;
+
+ // The displays last communicated to DisplayChangeNotifier.
+ std::vector<Display> old_displays_;
- // The timer to delay configuring outputs. See also the comments in
- // HandleDisplayReconfiguration().
- std::unique_ptr<base::OneShotTimer> configure_timer_;
+ // The timer to delay configuring outputs and notifying observers.
+ base::Timer configure_timer_;
DisplayChangeNotifier change_notifier_;
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698