Chromium Code Reviews| Index: ash/display/multi_display_manager.cc |
| diff --git a/ash/display/multi_display_manager.cc b/ash/display/multi_display_manager.cc |
| index 37509be0e82e2522f11a472ae805ca36da0b220d..b23e366267f8b0eb61a223dd858d64d7f272c79f 100644 |
| --- a/ash/display/multi_display_manager.cc |
| +++ b/ash/display/multi_display_manager.cc |
| @@ -30,16 +30,33 @@ |
| #endif |
| DECLARE_WINDOW_PROPERTY_TYPE(int64); |
| +typedef std::vector<gfx::Display> DisplayList; |
| namespace ash { |
| namespace internal { |
| namespace { |
| +struct DisplaySortFunctor { |
| + bool operator()(const gfx::Display& a, const gfx::Display& b) { |
| + return a.id() < b.id(); |
| + } |
| +}; |
| + |
| gfx::Display& GetInvalidDisplay() { |
| static gfx::Display* invalid_display = new gfx::Display(); |
| return *invalid_display; |
| } |
| +#if defined(OS_CHROMEOS) |
| +int64 GetDisplayIdForOutput(XID output) { |
| + uint16 manufacturer_id = 0; |
| + uint32 serial_number = 0; |
| + ui::GetOutputDeviceData( |
| + output, &manufacturer_id, &serial_number, NULL); |
| + return gfx::Display::GetID(manufacturer_id, serial_number); |
| +} |
| +#endif |
| + |
| } // namespace |
| using aura::RootWindow; |
| @@ -51,7 +68,8 @@ DEFINE_WINDOW_PROPERTY_KEY(int64, kDisplayIdKey, |
| gfx::Display::kInvalidDisplayID); |
| MultiDisplayManager::MultiDisplayManager() : |
| - internal_display_id_(gfx::Display::kInvalidDisplayID) { |
| + internal_display_id_(gfx::Display::kInvalidDisplayID), |
| + force_bounds_changed_(false) { |
| Init(); |
| } |
| @@ -82,19 +100,22 @@ void MultiDisplayManager::InitInternalDisplayInfo() { |
| for (size_t i = 0; i < output_names.size(); ++i) { |
| if (chromeos::OutputConfigurator::IsInternalOutputName( |
| output_names[i])) { |
| - XID internal_output = outputs[i]; |
| - uint16 manufacturer_id = 0; |
| - uint32 serial_number = 0; |
| - ui::GetOutputDeviceData( |
| - internal_output, &manufacturer_id, &serial_number, NULL); |
| - internal_display_id_ = |
| - gfx::Display::GetID(manufacturer_id, serial_number); |
| + internal_display_id_ = GetDisplayIdForOutput(outputs[i]); |
| return; |
| } |
| } |
| #endif |
| } |
| +bool MultiDisplayManager::IsActiveDisplay(const gfx::Display& display) const { |
| + for (DisplayList::const_iterator iter = displays_.begin(); |
| + iter != displays_.end(); ++iter) { |
| + if ((*iter).id() == display.id()) |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| bool MultiDisplayManager::HasInternalDisplay() const { |
| return internal_display_id_ != gfx::Display::kInvalidDisplayID; |
| } |
| @@ -111,7 +132,7 @@ bool MultiDisplayManager::UpdateWorkAreaOfDisplayNearestWindow( |
| const gfx::Display& MultiDisplayManager::FindDisplayContainingPoint( |
| const gfx::Point& point_in_screen) const { |
| - for (std::vector<gfx::Display>::const_iterator iter = displays_.begin(); |
| + for (DisplayList::const_iterator iter = displays_.begin(); |
| iter != displays_.end(); ++iter) { |
| const gfx::Display& display = *iter; |
| if (display.bounds().Contains(point_in_screen)) |
| @@ -135,10 +156,10 @@ void MultiDisplayManager::OnNativeDisplaysChanged( |
| // display list will be updated correctly. |
| return; |
| } |
| - std::vector<gfx::Display> new_displays; |
| + DisplayList new_displays = updated_displays; |
| if (internal_display_id_ != gfx::Display::kInvalidDisplayID) { |
| bool internal_display_connected = false; |
| - for (Displays::const_iterator iter = updated_displays.begin(); |
| + for (DisplayList::const_iterator iter = updated_displays.begin(); |
| iter != updated_displays.end(); ++iter) { |
| if ((*iter).id() == internal_display_id_) { |
| internal_display_connected = true; |
| @@ -151,48 +172,67 @@ void MultiDisplayManager::OnNativeDisplaysChanged( |
| // If the internal display wasn't connected, use the cached value. |
| if (!internal_display_connected) |
| new_displays.push_back(*internal_display_.get()); |
| - new_displays.insert( |
| - new_displays.end(), updated_displays.begin(), updated_displays.end()); |
| } else { |
| new_displays = updated_displays; |
| } |
| - size_t min = std::min(displays_.size(), new_displays.size()); |
| - |
| - // TODO(oshima): Fix this so that we can differentiate outputs |
| - // and keep a content on one display stays on the same display |
| - // when a display is added or removed. |
| - for (size_t i = 0; i < min; ++i) { |
| - gfx::Display& current_display = displays_[i]; |
| - const gfx::Display& new_display = new_displays[i]; |
| - if (current_display.bounds_in_pixel() != new_display.bounds_in_pixel() || |
| - current_display.device_scale_factor() != |
| - new_display.device_scale_factor()) { |
| - current_display.SetScaleAndBounds(new_display.device_scale_factor(), |
| - new_display.bounds_in_pixel()); |
| - NotifyBoundsChanged(current_display); |
| + std::sort(displays_.begin(), displays_.end(), DisplaySortFunctor()); |
| + std::sort(new_displays.begin(), new_displays.end(), DisplaySortFunctor()); |
| + |
| + DisplayList removed_displays; |
| + std::vector<size_t> changed_display_indices; |
| + std::vector<size_t> added_display_indices; |
| + |
| + DisplayList::iterator curr_iter = displays_.begin(); |
|
sky
2012/09/18 03:52:47
move iterators into for loop.
oshima
2012/09/18 09:30:48
Done.
|
| + DisplayList::iterator new_iter = new_displays.begin(); |
| + for (; curr_iter != displays_.end() || new_iter != new_displays.end();) { |
| + if (curr_iter == displays_.end()) { |
| + // more displays in new list. |
| + added_display_indices.push_back(new_iter - new_displays.begin()); |
| + ++new_iter; |
| + } else if (new_iter == new_displays.end()) { |
| + // more displays in current list. |
| + removed_displays.push_back(*curr_iter); |
| + ++curr_iter; |
| + } else if ((*curr_iter).id() == (*new_iter).id()) { |
| + const gfx::Display& current_display = *curr_iter; |
| + gfx::Display& new_display = *new_iter; |
| + if (force_bounds_changed_ || |
| + current_display.bounds_in_pixel() != new_display.bounds_in_pixel() || |
| + current_display.device_scale_factor() != |
| + new_display.device_scale_factor()) { |
| + changed_display_indices.push_back(new_iter - new_displays.begin()); |
| + } |
| + new_display.UpdateWorkAreaFromInsets(current_display.GetWorkAreaInsets()); |
| + ++curr_iter; |
| + ++new_iter; |
| + } else if ((*curr_iter).id() < (*new_iter).id()) { |
| + // more displays in current list between ids, which means it is deleted. |
| + removed_displays.push_back(*curr_iter); |
| + ++curr_iter; |
| + } else { |
| + // more displays in new list between ids, which means it is added. |
| + added_display_indices.push_back(new_iter - new_displays.begin()); |
| + ++new_iter; |
| } |
| } |
| - |
| - if (displays_.size() < new_displays.size()) { |
| - // New displays added |
| - for (size_t i = min; i < new_displays.size(); ++i) { |
| - const gfx::Display& new_display = new_displays[i]; |
| - displays_.push_back(gfx::Display(new_display.id())); |
| - gfx::Display& display = displays_.back(); |
| - display.SetScaleAndBounds(new_display.device_scale_factor(), |
| - new_display.bounds_in_pixel()); |
| - NotifyDisplayAdded(display); |
| - } |
| - } else { |
| - // Displays are removed. We keep the display for the primary |
| - // display (at index 0) because it needs the display information |
| - // even if it doesn't exit. |
| - while (displays_.size() > new_displays.size() && displays_.size() > 1) { |
| - Displays::reverse_iterator iter = displays_.rbegin(); |
| - NotifyDisplayRemoved(*iter); |
| - displays_.erase(iter.base() - 1); |
| - } |
| + displays_ = new_displays; |
| + // Temporarily add displays to be removed because display object |
| + // being removed are accessed during shutting the root. |
|
sky
2012/09/18 03:52:47
shutting down the root
oshima
2012/09/18 09:30:48
Done.
|
| + displays_.insert(displays_.end(), removed_displays.begin(), |
| + removed_displays.end()); |
| + for (std::vector<size_t>::iterator iter = changed_display_indices.begin(); |
| + iter != changed_display_indices.end(); ++iter) { |
| + NotifyBoundsChanged(displays_[*iter]); |
| + } |
| + for (std::vector<size_t>::iterator iter = added_display_indices.begin(); |
| + iter != added_display_indices.end(); ++iter) { |
| + NotifyDisplayAdded(displays_[*iter]); |
| + } |
| + for (DisplayList::const_reverse_iterator iter = removed_displays.rbegin(); |
| + iter != removed_displays.rend(); ++iter) { |
| + NotifyDisplayRemoved(displays_.back()); |
| + displays_.erase(displays_.end()); |
|
sky
2012/09/18 03:52:47
Don't you need displays_.end() - 1?
oshima
2012/09/18 09:30:48
I should have used pop_back()
|
| } |
| } |
| @@ -254,11 +294,11 @@ const gfx::Display& MultiDisplayManager::GetDisplayMatching( |
| return matching ? *matching : displays_[0]; |
| } |
| -std::string MultiDisplayManager::GetDisplayNameAt(size_t index) { |
| +std::string MultiDisplayManager::GetDisplayNameFor( |
| + const gfx::Display& display) { |
| #if defined(USE_X11) |
| - gfx::Display* display = GetDisplayAt(index); |
| std::vector<XID> outputs; |
| - if (display && display->id() != gfx::Display::kInvalidDisplayID && |
| + if (display.id() != gfx::Display::kInvalidDisplayID && |
| ui::GetOutputDeviceHandles(&outputs)) { |
| for (size_t i = 0; i < outputs.size(); ++i) { |
| uint16 manufacturer_id = 0; |
| @@ -266,15 +306,14 @@ std::string MultiDisplayManager::GetDisplayNameAt(size_t index) { |
| std::string name; |
| if (ui::GetOutputDeviceData( |
| outputs[i], &manufacturer_id, &serial_number, &name) && |
| - display->id() == |
| + display.id() == |
| gfx::Display::GetID(manufacturer_id, serial_number)) { |
| return name; |
| } |
| } |
| } |
| #endif |
| - |
| - return base::StringPrintf("Display %d", static_cast<int>(index + 1)); |
| + return base::StringPrintf("Display %d", static_cast<int>(display.id())); |
| } |
| void MultiDisplayManager::OnRootWindowResized(const aura::RootWindow* root, |
| @@ -307,8 +346,10 @@ void MultiDisplayManager::CycleDisplayImpl() { |
| if (displays_.size() > 1) { |
| // Remove if there is more than one display. |
| int count = displays_.size() - 1; |
| - for (Displays::const_iterator iter = displays_.begin(); count-- > 0; ++iter) |
| + for (DisplayList::const_iterator iter = displays_.begin(); |
| + count-- > 0; ++iter) { |
| new_displays.push_back(*iter); |
| + } |
| } else { |
| // Add if there is only one display. |
| new_displays.push_back(displays_[0]); |
| @@ -321,7 +362,7 @@ void MultiDisplayManager::CycleDisplayImpl() { |
| void MultiDisplayManager::ScaleDisplayImpl() { |
| if (displays_.size() > 0) { |
| std::vector<gfx::Display> new_displays; |
| - for (Displays::const_iterator iter = displays_.begin(); |
| + for (DisplayList::const_iterator iter = displays_.begin(); |
| iter != displays_.end(); ++iter) { |
| gfx::Display display = *iter; |
| float factor = display.device_scale_factor() == 1.0f ? 2.0f : 1.0f; |
| @@ -339,12 +380,16 @@ gfx::Display& MultiDisplayManager::FindDisplayForRootWindow( |
| int64 id = root_window->GetProperty(kDisplayIdKey); |
| // if id is |kInvaildDisplayID|, it's being deleted. |
| DCHECK(id != gfx::Display::kInvalidDisplayID); |
| - for (Displays::iterator iter = displays_.begin(); |
| + return FindDisplayForId(id); |
| +} |
| + |
| +gfx::Display& MultiDisplayManager::FindDisplayForId(int64 id) { |
| + for (DisplayList::iterator iter = displays_.begin(); |
| iter != displays_.end(); ++iter) { |
| if ((*iter).id() == id) |
| return *iter; |
| } |
| - DLOG(FATAL) << "Could not find display by id:" << id; |
| + DLOG(FATAL) << "Could not find display:" << id; |
| return GetInvalidDisplay(); |
| } |
| @@ -358,12 +403,20 @@ void MultiDisplayManager::AddDisplayFromSpec(const std::string& spec) { |
| displays_.push_back(display); |
| } |
| -int64 MultiDisplayManager::EnableInternalDisplayForTest() { |
| - const int64 kInternalDisplayIdForTest = 9999; |
| - internal_display_id_ = kInternalDisplayIdForTest; |
| - internal_display_.reset(new gfx::Display(internal_display_id_, |
| - gfx::Rect(800, 600))); |
| - return kInternalDisplayIdForTest; |
| +int64 MultiDisplayManager::SetFirstDisplayAsInternalDisplayForTest() { |
| + internal_display_id_ = displays_[0].id(); |
| + internal_display_.reset(new gfx::Display); |
| + *internal_display_ = displays_[0]; |
| + return internal_display_id_; |
| +} |
| + |
| +void MultiDisplayManager::SetDisplayIdsForTest(DisplayList* to_update) const { |
| + DisplayList::iterator iter_to_update = to_update->begin(); |
| + DisplayList::const_iterator iter = displays_.begin(); |
| + for (; iter != displays_.end() && iter_to_update != to_update->end(); |
| + ++iter, ++iter_to_update) { |
| + (*iter_to_update).set_id((*iter).id()); |
| + } |
| } |
| } // namespace internal |