| Index: ash/display/display_controller.cc
|
| diff --git a/ash/display/display_controller.cc b/ash/display/display_controller.cc
|
| index 11c76073eb2db87f056607ba0039c92537d0370f..0277844ecb24611875983d1c9e89957eb9ad9741 100644
|
| --- a/ash/display/display_controller.cc
|
| +++ b/ash/display/display_controller.cc
|
| @@ -9,7 +9,6 @@
|
| #include "ash/ash_switches.h"
|
| #include "ash/display/multi_display_manager.h"
|
| #include "ash/root_window_controller.h"
|
| -#include "ash/screen_ash.h"
|
| #include "ash/shell.h"
|
| #include "ash/wm/coordinate_conversion.h"
|
| #include "ash/wm/property_util.h"
|
| @@ -17,6 +16,7 @@
|
| #include "base/command_line.h"
|
| #include "base/json/json_value_converter.h"
|
| #include "base/string_piece.h"
|
| +#include "base/stringprintf.h"
|
| #include "base/values.h"
|
| #include "ui/aura/client/screen_position_client.h"
|
| #include "ui/aura/env.h"
|
| @@ -57,10 +57,28 @@ bool GetPositionFromString(const base::StringPiece& position,
|
| return true;
|
| }
|
| LOG(ERROR) << "Invalid position value: " << position;
|
| -
|
| return false;
|
| }
|
|
|
| +std::string GetStringFromPosition(DisplayLayout::Position position) {
|
| + switch (position) {
|
| + case DisplayLayout::TOP:
|
| + return std::string("top");
|
| + case DisplayLayout::BOTTOM:
|
| + return std::string("bottom");
|
| + case DisplayLayout::RIGHT:
|
| + return std::string("right");
|
| + case DisplayLayout::LEFT:
|
| + return std::string("left");
|
| + }
|
| + return std::string("unknown");
|
| +}
|
| +
|
| +internal::MultiDisplayManager* GetDisplayManager() {
|
| + return static_cast<internal::MultiDisplayManager*>(
|
| + aura::Env::GetInstance()->display_manager());
|
| +}
|
| +
|
| } // namespace
|
|
|
| DisplayLayout::DisplayLayout()
|
| @@ -81,6 +99,25 @@ DisplayLayout::DisplayLayout(DisplayLayout::Position position, int offset)
|
| DCHECK_GE(kMaxValidOffset, abs(offset));
|
| }
|
|
|
| +DisplayLayout DisplayLayout::Invert() const {
|
| + Position inverted_position = RIGHT;
|
| + switch (position) {
|
| + case TOP:
|
| + inverted_position = BOTTOM;
|
| + break;
|
| + case BOTTOM:
|
| + inverted_position = TOP;
|
| + break;
|
| + case RIGHT:
|
| + inverted_position = LEFT;
|
| + break;
|
| + case LEFT:
|
| + inverted_position = RIGHT;
|
| + break;
|
| + }
|
| + return DisplayLayout(inverted_position, -offset);
|
| +}
|
| +
|
| // static
|
| bool DisplayLayout::ConvertFromValue(const base::Value& value,
|
| DisplayLayout* layout) {
|
| @@ -95,29 +132,17 @@ bool DisplayLayout::ConvertToValue(const DisplayLayout& layout,
|
| if (!value->GetAsDictionary(&dict_value) || dict_value == NULL)
|
| return false;
|
|
|
| - std::string position_value;
|
| - switch (layout.position) {
|
| - case TOP:
|
| - position_value = "top";
|
| - break;
|
| - case BOTTOM:
|
| - position_value = "bottom";
|
| - break;
|
| - case RIGHT:
|
| - position_value = "right";
|
| - break;
|
| - case LEFT:
|
| - position_value = "left";
|
| - break;
|
| - default:
|
| - return false;
|
| - }
|
| -
|
| - dict_value->SetString("position", position_value);
|
| + const std::string position_str = GetStringFromPosition(layout.position);
|
| + dict_value->SetString("position", position_str);
|
| dict_value->SetInteger("offset", layout.offset);
|
| return true;
|
| }
|
|
|
| +std::string DisplayLayout::ToString() const {
|
| + const std::string position_str = GetStringFromPosition(position);
|
| + return StringPrintf("%s, %d", position_str.c_str(), offset);
|
| +}
|
| +
|
| // static
|
| void DisplayLayout::RegisterJSONConverter(
|
| base::JSONValueConverter<DisplayLayout>* converter) {
|
| @@ -127,11 +152,11 @@ void DisplayLayout::RegisterJSONConverter(
|
| }
|
|
|
| DisplayController::DisplayController() {
|
| - aura::Env::GetInstance()->display_manager()->AddObserver(this);
|
| + GetDisplayManager()->AddObserver(this);
|
| }
|
|
|
| DisplayController::~DisplayController() {
|
| - aura::Env::GetInstance()->display_manager()->RemoveObserver(this);
|
| + GetDisplayManager()->RemoveObserver(this);
|
| // Delete all root window controllers, which deletes root window
|
| // from the last so that the primary root window gets deleted last.
|
| for (std::map<int64, aura::RootWindow*>::const_reverse_iterator it =
|
| @@ -144,20 +169,40 @@ DisplayController::~DisplayController() {
|
| }
|
|
|
| void DisplayController::InitPrimaryDisplay() {
|
| - aura::DisplayManager* display_manager =
|
| - aura::Env::GetInstance()->display_manager();
|
| - const gfx::Display* display = display_manager->GetDisplayAt(0);
|
| - aura::RootWindow* root = AddRootWindowForDisplay(*display);
|
| - root->SetHostBounds(display->bounds_in_pixel());
|
| + const gfx::Display* primary_candidate = GetDisplayManager()->GetDisplayAt(0);
|
| +#if defined(OS_CHROMEOS)
|
| + if (base::chromeos::IsRunningOnChromeOS()) {
|
| + internal::MultiDisplayManager* display_manager = GetDisplayManager();
|
| + // On ChromeOS device, root windows are stacked vertically, and
|
| + // default primary is the one on top.
|
| + int count = display_manager->GetNumDisplays();
|
| + int y = primary_candidate->bounds_in_pixel().y();
|
| + for (int i = 1; i < count; ++i) {
|
| + const gfx::Display* display = display_manager->GetDisplayAt(i);
|
| + if (display_manager->IsInternalDisplayId(display->id())) {
|
| + primary_candidate = display;
|
| + break;
|
| + } else if (display->bounds_in_pixel().y() < y) {
|
| + primary_candidate = display;
|
| + y = display->bounds_in_pixel().y();
|
| + }
|
| + }
|
| + }
|
| +#endif
|
| + primary_display_ = *primary_candidate;
|
| + aura::RootWindow* root = AddRootWindowForDisplay(primary_display_);
|
| + root->SetHostBounds(primary_display_.bounds_in_pixel());
|
| + UpdateDisplayBoundsForLayout();
|
| }
|
|
|
| void DisplayController::InitSecondaryDisplays() {
|
| - aura::DisplayManager* display_manager =
|
| - aura::Env::GetInstance()->display_manager();
|
| - for (size_t i = 1; i < display_manager->GetNumDisplays(); ++i) {
|
| + internal::MultiDisplayManager* display_manager = GetDisplayManager();
|
| + for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
|
| const gfx::Display* display = display_manager->GetDisplayAt(i);
|
| - aura::RootWindow* root = AddRootWindowForDisplay(*display);
|
| - Shell::GetInstance()->InitRootWindowForSecondaryDisplay(root);
|
| + if (primary_display_.id() != display->id()) {
|
| + aura::RootWindow* root = AddRootWindowForDisplay(*display);
|
| + Shell::GetInstance()->InitRootWindowForSecondaryDisplay(root);
|
| + }
|
| }
|
| CommandLine* command_line = CommandLine::ForCurrentProcess();
|
| if (command_line->HasSwitch(switches::kAshSecondaryDisplayLayout)) {
|
| @@ -190,9 +235,7 @@ void DisplayController::RemoveObserver(Observer* observer) {
|
|
|
| aura::RootWindow* DisplayController::GetPrimaryRootWindow() {
|
| DCHECK(!root_windows_.empty());
|
| - aura::DisplayManager* display_manager =
|
| - aura::Env::GetInstance()->display_manager();
|
| - return root_windows_[display_manager->GetDisplayAt(0)->id()];
|
| + return root_windows_[primary_display_.id()];
|
| }
|
|
|
| aura::RootWindow* DisplayController::GetRootWindowForDisplayId(int64 id) {
|
| @@ -260,8 +303,9 @@ void DisplayController::SetLayoutForDisplayName(const std::string& name,
|
| }
|
| }
|
|
|
| -const DisplayLayout& DisplayController::GetLayoutForDisplayName(
|
| - const std::string& name) {
|
| +const DisplayLayout& DisplayController::GetLayoutForDisplay(
|
| + const gfx::Display& display) const {
|
| + const std::string& name = GetDisplayManager()->GetDisplayNameFor(display);
|
| std::map<std::string, DisplayLayout>::const_iterator it =
|
| secondary_layouts_.find(name);
|
|
|
| @@ -270,10 +314,84 @@ const DisplayLayout& DisplayController::GetLayoutForDisplayName(
|
| return default_display_layout_;
|
| }
|
|
|
| +const DisplayLayout& DisplayController::GetCurrentDisplayLayout() const {
|
| + DCHECK_EQ(2U, GetDisplayManager()->GetNumDisplays());
|
| + if (GetDisplayManager()->GetNumDisplays() > 1) {
|
| + DisplayController* non_const = const_cast<DisplayController*>(this);
|
| + return GetLayoutForDisplay(*(non_const->GetSecondaryDisplay()));
|
| + }
|
| + // On release build, just fallback to default instead of blowing up.
|
| + return default_display_layout_;
|
| +}
|
| +
|
| +void DisplayController::SetPrimaryDisplay(
|
| + const gfx::Display& new_primary_display) {
|
| + internal::MultiDisplayManager* display_manager = GetDisplayManager();
|
| + DCHECK(new_primary_display.is_valid());
|
| + DCHECK(display_manager->IsActiveDisplay(new_primary_display));
|
| +
|
| + if (!new_primary_display.is_valid() ||
|
| + !display_manager->IsActiveDisplay(new_primary_display)) {
|
| + LOG(ERROR) << "Invalid or non-existent display is requested:"
|
| + << new_primary_display.ToString();
|
| + return;
|
| + }
|
| +
|
| + if (primary_display_.id() == new_primary_display.id() ||
|
| + root_windows_.size() < 2) {
|
| + return;
|
| + }
|
| +
|
| + aura::RootWindow* non_primary_root = root_windows_[new_primary_display.id()];
|
| + LOG_IF(ERROR, !non_primary_root)
|
| + << "Unknown display is requested in SetPrimaryDisplay: id="
|
| + << new_primary_display.id();
|
| + if (!non_primary_root)
|
| + return;
|
| +
|
| + gfx::Display old_primary_display = primary_display_;
|
| +
|
| + // Swap root windows between current and new primary display.
|
| + aura::RootWindow* primary_root = root_windows_[primary_display_.id()];
|
| + DCHECK(primary_root);
|
| + DCHECK_NE(primary_root, non_primary_root);
|
| +
|
| + root_windows_[new_primary_display.id()] = primary_root;
|
| + primary_root->SetProperty(internal::kDisplayIdKey, new_primary_display.id());
|
| +
|
| + root_windows_[old_primary_display.id()] = non_primary_root;
|
| + non_primary_root->SetProperty(internal::kDisplayIdKey,
|
| + old_primary_display.id());
|
| +
|
| + primary_display_ = new_primary_display;
|
| +
|
| + // Update the layout.
|
| + SetLayoutForDisplayName(
|
| + display_manager->GetDisplayNameFor(old_primary_display),
|
| + GetLayoutForDisplay(new_primary_display).Invert());
|
| +
|
| + // Update the dispay manager with new display info.
|
| + std::vector<gfx::Display> displays;
|
| + displays.push_back(primary_display_);
|
| + displays.push_back(*GetSecondaryDisplay());
|
| + GetDisplayManager()->set_force_bounds_changed(true);
|
| + GetDisplayManager()->OnNativeDisplaysChanged(displays);
|
| + GetDisplayManager()->set_force_bounds_changed(false);
|
| +}
|
| +
|
| +gfx::Display* DisplayController::GetSecondaryDisplay() {
|
| + internal::MultiDisplayManager* display_manager = GetDisplayManager();
|
| + CHECK_EQ(2U, display_manager->GetNumDisplays());
|
| + return display_manager->GetDisplayAt(0)->id() == primary_display_.id() ?
|
| + display_manager->GetDisplayAt(1) : display_manager->GetDisplayAt(0);
|
| +}
|
| +
|
| void DisplayController::OnDisplayBoundsChanged(const gfx::Display& display) {
|
| + if (display.id() == primary_display_.id())
|
| + primary_display_ = display;
|
| NotifyDisplayConfigurationChanging();
|
| - root_windows_[display.id()]->SetHostBounds(display.bounds_in_pixel());
|
| UpdateDisplayBoundsForLayout();
|
| + root_windows_[display.id()]->SetHostBounds(display.bounds_in_pixel());
|
| }
|
|
|
| void DisplayController::OnDisplayAdded(const gfx::Display& display) {
|
| @@ -285,30 +403,45 @@ void DisplayController::OnDisplayAdded(const gfx::Display& display) {
|
| }
|
|
|
| void DisplayController::OnDisplayRemoved(const gfx::Display& display) {
|
| - aura::RootWindow* root = root_windows_[display.id()];
|
| - DCHECK(root);
|
| - // Primary display should never be removed by DisplayManager.
|
| - DCHECK(root != GetPrimaryRootWindow());
|
| + aura::RootWindow* root_to_delete = root_windows_[display.id()];
|
| + DCHECK(root_to_delete) << display.ToString();
|
| NotifyDisplayConfigurationChanging();
|
| +
|
| // Display for root window will be deleted when the Primary RootWindow
|
| // is deleted by the Shell.
|
| - if (root != GetPrimaryRootWindow()) {
|
| - root_windows_.erase(display.id());
|
| - internal::RootWindowController* controller =
|
| - GetRootWindowController(root);
|
| - DCHECK(controller);
|
| - controller->MoveWindowsTo(GetPrimaryRootWindow());
|
| - // Delete most of root window related objects, but don't delete
|
| - // root window itself yet because the stak may be using it.
|
| - controller->Shutdown();
|
| - MessageLoop::current()->DeleteSoon(FROM_HERE, controller);
|
| + root_windows_.erase(display.id());
|
| +
|
| + // When the primary root window's display is removed, move the primary
|
| + // root to the other display.
|
| + if (primary_display_.id() == display.id()) {
|
| + DCHECK_EQ(1U, root_windows_.size());
|
| + primary_display_ = *GetSecondaryDisplay();
|
| + aura::RootWindow* primary_root = root_to_delete;
|
| +
|
| + // Delete the other root instead.
|
| + root_to_delete = root_windows_[primary_display_.id()];
|
| + root_to_delete->SetProperty(internal::kDisplayIdKey, display.id());
|
| +
|
| + // Setup primary root.
|
| + root_windows_[primary_display_.id()] = primary_root;
|
| + primary_root->SetProperty(internal::kDisplayIdKey, primary_display_.id());
|
| +
|
| + OnDisplayBoundsChanged(primary_display_);
|
| }
|
| + internal::RootWindowController* controller =
|
| + GetRootWindowController(root_to_delete);
|
| + DCHECK(controller);
|
| + controller->MoveWindowsTo(GetPrimaryRootWindow());
|
| + // Delete most of root window related objects, but don't delete
|
| + // root window itself yet because the stak may be using it.
|
| + controller->Shutdown();
|
| + MessageLoop::current()->DeleteSoon(FROM_HERE, controller);
|
| }
|
|
|
| aura::RootWindow* DisplayController::AddRootWindowForDisplay(
|
| const gfx::Display& display) {
|
| - aura::RootWindow* root = aura::Env::GetInstance()->display_manager()->
|
| - CreateRootWindowForDisplay(display);
|
| + aura::RootWindow* root =
|
| + GetDisplayManager()->CreateRootWindowForDisplay(display);
|
| root_windows_[display.id()] = root;
|
|
|
| #if defined(OS_CHROMEOS)
|
| @@ -326,25 +459,18 @@ void DisplayController::UpdateDisplayBoundsForLayout() {
|
| return;
|
|
|
| DCHECK_EQ(2, gfx::Screen::GetNumDisplays());
|
| - aura::DisplayManager* display_manager =
|
| - aura::Env::GetInstance()->display_manager();
|
| - const gfx::Rect& primary_bounds = display_manager->GetDisplayAt(0)->bounds();
|
| - gfx::Display* secondary_display = display_manager->GetDisplayAt(1);
|
| - const std::string& secondary_name = display_manager->GetDisplayNameAt(1);
|
| + const gfx::Rect& primary_bounds = primary_display_.bounds();
|
| +
|
| + gfx::Display* secondary_display = GetSecondaryDisplay();
|
| const gfx::Rect& secondary_bounds = secondary_display->bounds();
|
| gfx::Point new_secondary_origin = primary_bounds.origin();
|
|
|
| - const DisplayLayout* layout = &default_display_layout_;
|
| - std::map<std::string, DisplayLayout>::const_iterator iter =
|
| - secondary_layouts_.find(secondary_name);
|
| - if (iter != secondary_layouts_.end())
|
| - layout = &iter->second;
|
| -
|
| - DisplayLayout::Position position = layout->position;
|
| + const DisplayLayout& layout = GetLayoutForDisplay(*secondary_display);
|
| + DisplayLayout::Position position = layout.position;
|
|
|
| // Ignore the offset in case the secondary display doesn't share edges with
|
| // the primary display.
|
| - int offset = layout->offset;
|
| + int offset = layout.offset;
|
| if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) {
|
| offset = std::min(
|
| offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset);
|
|
|