| 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..79729f159c829bed60e75cc6c4d774b940fc9a9d 100644
|
| --- a/ash/display/multi_display_manager.cc
|
| +++ b/ash/display/multi_display_manager.cc
|
| @@ -8,6 +8,7 @@
|
| #include <vector>
|
|
|
| #include "ash/display/display_controller.h"
|
| +#include "ash/shell.h"
|
| #include "base/command_line.h"
|
| #include "base/stl_util.h"
|
| #include "base/string_split.h"
|
| @@ -18,6 +19,7 @@
|
| #include "ui/aura/root_window_host.h"
|
| #include "ui/aura/window_property.h"
|
| #include "ui/gfx/display.h"
|
| +#include "ui/gfx/screen.h"
|
| #include "ui/gfx/rect.h"
|
|
|
| #if defined(USE_X11)
|
| @@ -30,16 +32,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 +70,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();
|
| }
|
|
|
| @@ -72,33 +92,23 @@ void MultiDisplayManager::ToggleDisplayScale() {
|
| manager->ScaleDisplayImpl();
|
| }
|
|
|
| -void MultiDisplayManager::InitInternalDisplayInfo() {
|
| -#if defined(OS_CHROMEOS)
|
| - if (!base::chromeos::IsRunningOnChromeOS())
|
| - return;
|
| - std::vector<XID> outputs;
|
| - ui::GetOutputDeviceHandles(&outputs);
|
| - std::vector<std::string> output_names = ui::GetOutputNames(outputs);
|
| - 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);
|
| - return;
|
| - }
|
| +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;
|
| }
|
| -#endif
|
| + return false;
|
| }
|
|
|
| bool MultiDisplayManager::HasInternalDisplay() const {
|
| return internal_display_id_ != gfx::Display::kInvalidDisplayID;
|
| }
|
|
|
| +bool MultiDisplayManager::IsInternalDisplayId(int64 id) const {
|
| + return internal_display_id_ == id;
|
| +}
|
| +
|
| bool MultiDisplayManager::UpdateWorkAreaOfDisplayNearestWindow(
|
| const aura::Window* window,
|
| const gfx::Insets& insets) {
|
| @@ -111,7 +121,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))
|
| @@ -122,7 +132,7 @@ const gfx::Display& MultiDisplayManager::FindDisplayContainingPoint(
|
|
|
| void MultiDisplayManager::OnNativeDisplaysChanged(
|
| const std::vector<gfx::Display>& updated_displays) {
|
| - if (updated_displays.size() == 0) {
|
| + if (updated_displays.empty()) {
|
| // Don't update the displays when all displays are disconnected.
|
| // This happens when:
|
| // - the device is idle and powerd requested to turn off all displays.
|
| @@ -135,10 +145,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;
|
| @@ -149,50 +159,88 @@ void MultiDisplayManager::OnNativeDisplaysChanged(
|
| }
|
| }
|
| // If the internal display wasn't connected, use the cached value.
|
| - if (!internal_display_connected)
|
| + if (!internal_display_connected) {
|
| + // Internal display may be reported as disconnect during startup time.
|
| + if (!internal_display_.get()) {
|
| + internal_display_.reset(new gfx::Display(internal_display_id_,
|
| + gfx::Rect(800, 600)));
|
| + }
|
| 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;
|
| + gfx::Display current_primary;
|
| + if (Shell::HasInstance())
|
| + current_primary = gfx::Screen::GetPrimaryDisplay();
|
| +
|
| + for (DisplayList::iterator curr_iter = displays_.begin(),
|
| + new_iter = new_displays.begin();
|
| + 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());
|
| + }
|
| + // TODO(oshima): This is ugly. Simplify these operations.
|
| + new_display.SetScaleAndBounds(
|
| + new_display.device_scale_factor(),
|
| + new_display.bounds_in_pixel());
|
| + // If the display is primary, then simpy use 0,0. Otherwise,
|
| + // use the origin currently used.
|
| + if ((*new_iter).id() != current_primary.id()) {
|
| + new_display.set_bounds(gfx::Rect(current_display.bounds().origin(),
|
| + new_display.bounds().size()));
|
| + }
|
| + 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;
|
| }
|
| }
|
| + displays_ = new_displays;
|
| + // Temporarily add displays to be removed because display object
|
| + // being removed are accessed during shutting down the root.
|
| + 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]);
|
| + }
|
|
|
| - 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);
|
| - }
|
| + for (DisplayList::const_reverse_iterator iter = removed_displays.rbegin();
|
| + iter != removed_displays.rend(); ++iter) {
|
| + NotifyDisplayRemoved(displays_.back());
|
| + displays_.pop_back();
|
| }
|
| }
|
|
|
| @@ -254,11 +302,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 +314,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,
|
| @@ -289,6 +336,21 @@ void MultiDisplayManager::OnRootWindowResized(const aura::RootWindow* root,
|
| }
|
|
|
| void MultiDisplayManager::Init() {
|
| +#if defined(OS_CHROMEOS)
|
| + if (base::chromeos::IsRunningOnChromeOS()) {
|
| + std::vector<XID> outputs;
|
| + ui::GetOutputDeviceHandles(&outputs);
|
| + std::vector<std::string> output_names = ui::GetOutputNames(outputs);
|
| + for (size_t i = 0; i < output_names.size(); ++i) {
|
| + if (chromeos::OutputConfigurator::IsInternalOutputName(
|
| + output_names[i])) {
|
| + internal_display_id_ = GetDisplayIdForOutput(outputs[i]);
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +#endif
|
| +
|
| // TODO(oshima): Move this logic to DisplayChangeObserver.
|
| const string size_str = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
|
| switches::kAuraHostWindowSize);
|
| @@ -307,8 +369,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 +385,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 +403,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 +426,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
|
|
|