summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
authoroshima <oshima@chromium.org>2015-04-27 16:27:03 -0700
committerCommit bot <commit-bot@chromium.org>2015-04-27 23:27:21 +0000
commit55ef921cb46ae2b1a95ddda8a376120db53eee69 (patch)
treed3b7ca8e0b457fe20567851b820ba5a6cdb5f77c /ash
parent172214038410fb835cc36721fcc2dc7b7a7dd5fd (diff)
downloadchromium_src-55ef921cb46ae2b1a95ddda8a376120db53eee69.zip
chromium_src-55ef921cb46ae2b1a95ddda8a376120db53eee69.tar.gz
chromium_src-55ef921cb46ae2b1a95ddda8a376120db53eee69.tar.bz2
Add unified desktop flag "--ash-enable-unified-desktop"
Enhanced MirrorWindowController to manage multiple mirroring windows. BUG=365662 Review URL: https://codereview.chromium.org/1107733006 Cr-Commit-Position: refs/heads/master@{#327172}
Diffstat (limited to 'ash')
-rw-r--r--ash/ash.gyp2
-rw-r--r--ash/ash_switches.cc24
-rw-r--r--ash/ash_switches.h8
-rw-r--r--ash/display/display_controller.cc108
-rw-r--r--ash/display/display_controller.h11
-rw-r--r--ash/display/display_manager.cc177
-rw-r--r--ash/display/display_manager.h44
-rw-r--r--ash/display/display_manager_unittest.cc40
-rw-r--r--ash/display/mirror_window_controller.cc231
-rw-r--r--ash/display/mirror_window_controller.h20
-rw-r--r--ash/display/mirror_window_controller_unittest.cc14
-rw-r--r--ash/display/root_window_transformers.cc37
-rw-r--r--ash/display/root_window_transformers.h8
-rw-r--r--ash/display/root_window_transformers_unittest.cc2
-rw-r--r--ash/display/screen_ash.cc5
-rw-r--r--ash/host/ash_window_tree_host.h2
-rw-r--r--ash/host/ash_window_tree_host_init_params.cc8
-rw-r--r--ash/host/ash_window_tree_host_init_params.h2
-rw-r--r--ash/host/ash_window_tree_host_ozone.cc3
-rw-r--r--ash/host/ash_window_tree_host_unified.cc164
-rw-r--r--ash/host/ash_window_tree_host_unified.h75
-rw-r--r--ash/host/ash_window_tree_host_x11.cc3
-rw-r--r--ash/shell.cc4
-rw-r--r--ash/system/web_notification/web_notification_tray_unittest.cc4
-rw-r--r--ash/touch/touch_transformer_controller.cc3
25 files changed, 799 insertions, 200 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp
index ff45e6c..14b2192 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -148,6 +148,8 @@
'host/ash_window_tree_host_init_params.cc',
'host/ash_window_tree_host_init_params.h',
'host/ash_window_tree_host_ozone.cc',
+ 'host/ash_window_tree_host_unified.cc',
+ 'host/ash_window_tree_host_unified.h',
'host/ash_window_tree_host_win.cc',
'host/ash_window_tree_host_x11.cc',
'host/ash_window_tree_host_x11.h',
diff --git a/ash/ash_switches.cc b/ash/ash_switches.cc
index 4ab34f8..7f052dc 100644
--- a/ash/ash_switches.cc
+++ b/ash/ash_switches.cc
@@ -5,6 +5,7 @@
#include "ash/ash_switches.h"
#include "base/command_line.h"
+#include "base/sys_info.h"
namespace ash {
namespace switches {
@@ -17,9 +18,6 @@ namespace switches {
const char kAshAnimateFromBootSplashScreen[] =
"ash-animate-from-boot-splash-screen";
-// Constrains the pointer movement within a root window on desktop.
-const char kAshConstrainPointerToRoot[] = "ash-constrain-pointer-to-root";
-
// Copies the host window's content to the system background layer at startup.
// Can make boot slightly slower, but also hides an even-longer awkward period
// where we display a white background if the login wallpaper takes a long time
@@ -56,6 +54,7 @@ const char kAshEnableFullscreenAppList[] = "ash-enable-fullscreen-app-list";
// Enables key bindings to scroll magnified screen.
const char kAshEnableMagnifierKeyScroller[] =
"ash-enable-magnifier-key-scroller";
+
#endif
// Enables mirrored screen.
@@ -122,5 +121,24 @@ const char kForceAshToDesktop[] = "ash-force-desktop";
#endif
+#if defined(OS_CHROMEOS)
+// Constrains the pointer movement within a root window on desktop.
+bool ConstrainPointerToRoot() {
+ const char kAshConstrainPointerToRoot[] = "ash-constrain-pointer-to-root";
+
+ return base::SysInfo::IsRunningOnChromeOS() ||
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ kAshConstrainPointerToRoot);
+}
+
+// Enables unified desktop mode.
+bool UnifiedDesktopEnabled() {
+ const char kAshEnableUnifiedDesktop[] = "ash-enable-unified-desktop";
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ kAshEnableUnifiedDesktop);
+}
+
+#endif
+
} // namespace switches
} // namespace ash
diff --git a/ash/ash_switches.h b/ash/ash_switches.h
index 40aba02..171272f 100644
--- a/ash/ash_switches.h
+++ b/ash/ash_switches.h
@@ -18,7 +18,6 @@ namespace switches {
// Please keep alphabetized.
ASH_EXPORT extern const char kAshAnimateFromBootSplashScreen[];
-ASH_EXPORT extern const char kAshConstrainPointerToRoot[];
ASH_EXPORT extern const char kAshCopyHostBackgroundAtBoot[];
ASH_EXPORT extern const char kAshDebugShortcuts[];
ASH_EXPORT extern const char kAshDisableLockLayoutManager[];
@@ -47,6 +46,13 @@ ASH_EXPORT extern const char kAuraLegacyPowerButton[];
ASH_EXPORT extern const char kForceAshToDesktop[];
#endif
+#if defined(OS_CHROMEOS)
+// True if the pointer (cursor) position should be kept inside root windows.
+ASH_EXPORT bool ConstrainPointerToRoot();
+
+ASH_EXPORT bool UnifiedDesktopEnabled();
+#endif
+
} // namespace switches
} // namespace ash
diff --git a/ash/display/display_controller.cc b/ash/display/display_controller.cc
index 304b927..2aa2fc6 100644
--- a/ash/display/display_controller.cc
+++ b/ash/display/display_controller.cc
@@ -160,8 +160,7 @@ void SetDisplayPropertiesOnHost(AshWindowTreeHost* ash_host,
host->compositor()->ScheduleFullRedraw();
}
-void ClearDisplayPropertiesOnHost(AshWindowTreeHost* ash_host,
- const gfx::Display& display) {
+void ClearDisplayPropertiesOnHost(AshWindowTreeHost* ash_host) {
#if defined(OS_CHROMEOS) && defined(USE_OZONE)
aura::WindowTreeHost* host = ash_host->AsWindowTreeHost();
ui::CursorController::GetInstance()->ClearCursorConfigForWindow(
@@ -181,12 +180,11 @@ aura::Window* GetWindow(AshWindowTreeHost* ash_host) {
class FocusActivationStore {
public:
FocusActivationStore()
- : activation_client_(NULL),
- capture_client_(NULL),
- focus_client_(NULL),
- focused_(NULL),
- active_(NULL) {
- }
+ : activation_client_(nullptr),
+ capture_client_(nullptr),
+ focus_client_(nullptr),
+ focused_(nullptr),
+ active_(nullptr) {}
void Store(bool clear_focus) {
if (!activation_client_) {
@@ -207,13 +205,13 @@ class FocusActivationStore {
activation_client_->DeactivateWindow(active_);
// Release capture if any.
- capture_client_->SetCapture(NULL);
+ capture_client_->SetCapture(nullptr);
// Clear the focused window if any. This is necessary because a
// window may be deleted when losing focus (fullscreen flash for
// example). If the focused window is still alive after move, it'll
// be re-focused below.
if (clear_focus)
- focus_client_->FocusWindow(NULL);
+ focus_client_->FocusWindow(nullptr);
}
void Restore() {
@@ -227,8 +225,8 @@ class FocusActivationStore {
tracker_.Remove(focused_);
if (active_)
tracker_.Remove(active_);
- focused_ = NULL;
- active_ = NULL;
+ focused_ = nullptr;
+ active_ = nullptr;
}
private:
@@ -263,7 +261,7 @@ bool DisplayController::DisplayChangeLimiter::IsThrottled() const {
// DisplayController
DisplayController::DisplayController()
- : primary_tree_host_for_replace_(NULL),
+ : primary_tree_host_for_replace_(nullptr),
focus_activation_store_(new FocusActivationStore()),
cursor_window_controller_(new CursorWindowController()),
mirror_window_controller_(new MirrorWindowController()),
@@ -289,7 +287,7 @@ void DisplayController::Start() {
void DisplayController::Shutdown() {
// Unset the display manager's delegate here because
// DisplayManager outlives DisplayController.
- Shell::GetInstance()->display_manager()->set_delegate(NULL);
+ Shell::GetInstance()->display_manager()->set_delegate(nullptr);
cursor_window_controller_.reset();
mirror_window_controller_.reset();
@@ -302,7 +300,7 @@ void DisplayController::Shutdown() {
// delete the primary root window controller.
aura::Window::Windows root_windows = DisplayController::GetAllRootWindows();
std::vector<RootWindowController*> to_delete;
- RootWindowController* primary_rwc = NULL;
+ RootWindowController* primary_rwc = nullptr;
for (aura::Window::Windows::iterator iter = root_windows.begin();
iter != root_windows.end();
++iter) {
@@ -330,7 +328,6 @@ void DisplayController::CreatePrimaryHost(
void DisplayController::InitDisplays() {
RootWindowController::CreateForPrimaryDisplay(
window_tree_hosts_[primary_display_id]);
-
DisplayManager* display_manager = GetDisplayManager();
for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
const gfx::Display& display = display_manager->GetDisplayAt(i);
@@ -363,12 +360,17 @@ aura::Window* DisplayController::GetPrimaryRootWindow() {
}
aura::Window* DisplayController::GetRootWindowForDisplayId(int64 id) {
- CHECK_EQ(1u, window_tree_hosts_.count(id));
- AshWindowTreeHost* host = window_tree_hosts_[id];
+ AshWindowTreeHost* host = GetAshWindowTreeHostForDisplayId(id);
CHECK(host);
return GetWindow(host);
}
+AshWindowTreeHost* DisplayController::GetAshWindowTreeHostForDisplayId(
+ int64 id) {
+ CHECK_EQ(1u, window_tree_hosts_.count(id));
+ return window_tree_hosts_[id];
+}
+
void DisplayController::CloseChildWindows() {
for (WindowTreeHostMap::const_iterator it = window_tree_hosts_.begin();
it != window_tree_hosts_.end();
@@ -546,7 +548,7 @@ void DisplayController::UpdateMouseLocationAfterDisplayChange() {
int64 closest_distance_squared = -1;
DisplayManager* display_manager = GetDisplayManager();
- aura::Window* dst_root_window = NULL;
+ aura::Window* dst_root_window = nullptr;
for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
const gfx::Display& display = display_manager->GetDisplayAt(i);
const DisplayInfo display_info =
@@ -629,13 +631,30 @@ bool DisplayController::UpdateWorkAreaOfDisplayNearestWindow(
}
void DisplayController::OnDisplayAdded(const gfx::Display& display) {
- if (primary_tree_host_for_replace_) {
+ if (GetDisplayManager()->IsInUnifiedMode()) {
+ if (primary_display_id == gfx::Display::kInvalidDisplayID)
+ primary_display_id = display.id();
+ AshWindowTreeHost* ash_host =
+ AddWindowTreeHostForDisplay(display, AshWindowTreeHostInitParams());
+ RootWindowController::CreateForSecondaryDisplay(ash_host);
+
+ if (primary_tree_host_for_replace_) {
+ AshWindowTreeHost* to_delete = primary_tree_host_for_replace_;
+ primary_tree_host_for_replace_ = nullptr;
+ DeleteHost(to_delete);
+ // the host has already been removed from the window_tree_host_.
+ }
+ }
+ // TODO(oshima): It should be possible to consolidate logic for
+ // unified and non unified, but I'm keeping them separated to minimize
+ // the risk in M44. I'll consolidate this in M45.
+ else if (primary_tree_host_for_replace_) {
DCHECK(window_tree_hosts_.empty());
primary_display_id = display.id();
window_tree_hosts_[display.id()] = primary_tree_host_for_replace_;
GetRootWindowSettings(GetWindow(primary_tree_host_for_replace_))
->display_id = display.id();
- primary_tree_host_for_replace_ = NULL;
+ primary_tree_host_for_replace_ = nullptr;
const DisplayInfo& display_info =
GetDisplayManager()->GetDisplayInfo(display.id());
AshWindowTreeHost* ash_host = window_tree_hosts_[display.id()];
@@ -645,12 +664,24 @@ void DisplayController::OnDisplayAdded(const gfx::Display& display) {
if (primary_display_id == gfx::Display::kInvalidDisplayID)
primary_display_id = display.id();
DCHECK(!window_tree_hosts_.empty());
- AshWindowTreeHost* ash_host = AddWindowTreeHostForDisplay(
- display, AshWindowTreeHostInitParams());
+ AshWindowTreeHost* ash_host =
+ AddWindowTreeHostForDisplay(display, AshWindowTreeHostInitParams());
RootWindowController::CreateForSecondaryDisplay(ash_host);
}
}
+void DisplayController::DeleteHost(AshWindowTreeHost* host_to_delete) {
+ ClearDisplayPropertiesOnHost(host_to_delete);
+ RootWindowController* controller =
+ GetRootWindowController(GetWindow(host_to_delete));
+ DCHECK(controller);
+ controller->MoveWindowsTo(GetPrimaryRootWindow());
+ // Delete most of root window related objects, but don't delete
+ // root window itself yet because the stack may be using it.
+ controller->Shutdown();
+ base::MessageLoop::current()->DeleteSoon(FROM_HERE, controller);
+}
+
void DisplayController::OnDisplayRemoved(const gfx::Display& display) {
AshWindowTreeHost* host_to_delete = window_tree_hosts_[display.id()];
CHECK(host_to_delete) << display.ToString();
@@ -690,15 +721,8 @@ void DisplayController::OnDisplayRemoved(const gfx::Display& display) {
GetDisplayManager()->GetDisplayForId(primary_display_id),
DISPLAY_METRIC_BOUNDS);
}
- ClearDisplayPropertiesOnHost(host_to_delete, display);
- RootWindowController* controller =
- GetRootWindowController(GetWindow(host_to_delete));
- DCHECK(controller);
- controller->MoveWindowsTo(GetPrimaryRootWindow());
- // Delete most of root window related objects, but don't delete
- // root window itself yet because the stack may be using it.
- controller->Shutdown();
- base::MessageLoop::current()->DeleteSoon(FROM_HERE, controller);
+
+ DeleteHost(host_to_delete);
// The window tree host should be erased at last because some handlers can
// access to the host through GetRootWindowForDisplayId() during
@@ -731,10 +755,11 @@ void DisplayController::OnHostResized(const aura::WindowTreeHost* host) {
}
void DisplayController::CreateOrUpdateMirroringDisplay(
- const DisplayInfo& info) {
- switch (GetDisplayManager()->second_display_mode()) {
+ const DisplayInfoList& info_list) {
+ switch (GetDisplayManager()->multi_display_mode()) {
case DisplayManager::MIRRORING:
- mirror_window_controller_->UpdateWindow(info);
+ case DisplayManager::UNIFIED:
+ mirror_window_controller_->UpdateWindow(info_list);
cursor_window_controller_->UpdateContainer();
break;
case DisplayManager::EXTENDED:
@@ -780,9 +805,9 @@ void DisplayController::PostDisplayConfigurationChange() {
if (display_manager->num_connected_displays() > 1) {
DisplayIdPair pair = display_manager->GetCurrentDisplayIdPair();
layout_store->UpdateMirrorStatus(pair, display_manager->IsInMirrorMode());
- DisplayLayout layout = layout_store->GetRegisteredDisplayLayout(pair);
if (Shell::GetScreen()->GetNumDisplays() > 1 ) {
+ DisplayLayout layout = layout_store->GetRegisteredDisplayLayout(pair);
int64 primary_id = layout.primary_id;
SetPrimaryDisplayId(
primary_id == gfx::Display::kInvalidDisplayID ?
@@ -807,10 +832,14 @@ AshWindowTreeHost* DisplayController::AddWindowTreeHostForDisplay(
GetDisplayManager()->GetDisplayInfo(display.id());
AshWindowTreeHostInitParams params_with_bounds(init_params);
params_with_bounds.initial_bounds = display_info.bounds_in_native();
+ params_with_bounds.offscreen =
+ display.id() == DisplayManager::kUnifiedDisplayId;
AshWindowTreeHost* ash_host = AshWindowTreeHost::Create(params_with_bounds);
aura::WindowTreeHost* host = ash_host->AsWindowTreeHost();
- host->window()->SetName(base::StringPrintf("RootWindow-%d", host_count++));
+ host->window()->SetName(base::StringPrintf(
+ "%sRootWindow-%d", params_with_bounds.offscreen ? "Offscreen" : "",
+ host_count++));
host->window()->SetTitle(base::UTF8ToUTF16(display_info.name()));
host->compositor()->SetBackgroundColor(SK_ColorBLACK);
// No need to remove our observer observer because the DisplayController
@@ -823,10 +852,7 @@ AshWindowTreeHost* DisplayController::AddWindowTreeHostForDisplay(
SetDisplayPropertiesOnHost(ash_host, display);
#if defined(OS_CHROMEOS)
- static bool force_constrain_pointer_to_root =
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAshConstrainPointerToRoot);
- if (base::SysInfo::IsRunningOnChromeOS() || force_constrain_pointer_to_root)
+ if (switches::ConstrainPointerToRoot())
ash_host->ConfineCursorToRootWindow();
#endif
return ash_host;
diff --git a/ash/display/display_controller.h b/ash/display/display_controller.h
index 3dc8189..a46b8d1 100644
--- a/ash/display/display_controller.h
+++ b/ash/display/display_controller.h
@@ -106,6 +106,10 @@ class ASH_EXPORT DisplayController : public gfx::DisplayObserver,
// Returns the root window for |display_id|.
aura::Window* GetRootWindowForDisplayId(int64 id);
+ // Returns AshWTH for given display |id|. Call results in CHECK failure
+ // if the WTH does not exist.
+ AshWindowTreeHost* GetAshWindowTreeHostForDisplayId(int64 id);
+
// Toggle mirror mode.
void ToggleMirrorMode();
@@ -153,7 +157,8 @@ class ASH_EXPORT DisplayController : public gfx::DisplayObserver,
void OnHostResized(const aura::WindowTreeHost* host) override;
// aura::DisplayManager::Delegate overrides:
- void CreateOrUpdateMirroringDisplay(const DisplayInfo& info) override;
+ void CreateOrUpdateMirroringDisplay(
+ const DisplayInfoList& info_list) override;
void CloseMirroringDisplay() override;
void PreDisplayConfigurationChange(bool clear_focus) override;
void PostDisplayConfigurationChange() override;
@@ -174,6 +179,10 @@ class ASH_EXPORT DisplayController : public gfx::DisplayObserver,
void SetMirrorModeAfterAnimation(bool mirror);
+ // Delete the AsWindowTreeHost. This does not remove the entry from
+ // |window_tree_hosts_|. Caller has to explicitly remove it.
+ void DeleteHost(AshWindowTreeHost* host_to_delete);
+
class DisplayChangeLimiter {
public:
DisplayChangeLimiter();
diff --git a/ash/display/display_manager.cc b/ash/display/display_manager.cc
index f4f344f..aaee923 100644
--- a/ash/display/display_manager.cc
+++ b/ash/display/display_manager.cc
@@ -49,6 +49,8 @@
#include "base/win/windows_version.h"
#endif
+#include "base/debug/stack_trace.h"
+
namespace ash {
typedef std::vector<gfx::Display> DisplayList;
typedef std::vector<DisplayInfo> DisplayInfoList;
@@ -115,6 +117,9 @@ bool IsInternalDisplayId(int64 id) {
using std::string;
using std::vector;
+// static
+int64 DisplayManager::kUnifiedDisplayId = -10;
+
DisplayManager::DisplayManager()
: delegate_(NULL),
screen_(new ScreenAsh),
@@ -123,7 +128,8 @@ DisplayManager::DisplayManager()
num_connected_displays_(0),
force_bounds_changed_(false),
change_display_upon_host_resize_(false),
- second_display_mode_(EXTENDED),
+ multi_display_mode_(EXTENDED),
+ default_multi_display_mode_(EXTENDED),
mirroring_display_id_(gfx::Display::kInvalidDisplayID),
registered_internal_display_rotation_lock_(false),
registered_internal_display_rotation_(gfx::Display::ROTATE_0),
@@ -133,6 +139,9 @@ DisplayManager::DisplayManager()
if (base::SysInfo::IsRunningOnChromeOS())
DisplayInfo::SetUse125DSFForUIScaling(true);
+ if (switches::UnifiedDesktopEnabled())
+ multi_display_mode_ = default_multi_display_mode_ = UNIFIED;
+
change_display_upon_host_resize_ = !base::SysInfo::IsRunningOnChromeOS();
#endif
gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_ALTERNATE, screen_.get());
@@ -170,7 +179,7 @@ bool DisplayManager::InitFromCommandLine() {
MaybeInitInternalDisplay(&info_list[0]);
if (info_list.size() > 1 &&
command_line->HasSwitch(switches::kAshEnableSoftwareMirroring)) {
- SetSecondDisplayMode(MIRRORING);
+ SetMultiDisplayMode(MIRRORING);
}
OnNativeDisplaysChanged(info_list);
return true;
@@ -219,7 +228,10 @@ DisplayLayout DisplayManager::GetCurrentDisplayLayout() {
}
DisplayIdPair DisplayManager::GetCurrentDisplayIdPair() const {
- if (IsInMirrorMode()) {
+ if (IsInUnifiedMode()) {
+ return std::make_pair(software_mirroring_display_list_[0].id(),
+ software_mirroring_display_list_[1].id());
+ } else if (IsInMirrorMode()) {
if (software_mirroring_enabled()) {
CHECK_EQ(2u, num_connected_displays());
// This comment is to make it easy to distinguish the crash
@@ -593,7 +605,7 @@ void DisplayManager::OnNativeDisplaysChanged(
bool internal_display_connected = false;
num_connected_displays_ = updated_displays.size();
mirroring_display_id_ = gfx::Display::kInvalidDisplayID;
- software_mirroring_display_ = gfx::Display();
+ software_mirroring_display_list_.clear();
DisplayInfoList new_display_info_list;
for (DisplayInfoList::const_iterator iter = updated_displays.begin();
iter != updated_displays.end();
@@ -668,8 +680,7 @@ void DisplayManager::UpdateDisplays(
if (delegate_)
delegate_->CloseMirroringDisplay();
- if (second_display_mode_ == MIRRORING && new_display_info_list.size() == 2)
- CreateSoftwareMirroringDisplay(&new_display_info_list);
+ CreateSoftwareMirroringDisplay(&new_display_info_list);
DisplayList new_displays;
DisplayList removed_displays;
@@ -870,6 +881,11 @@ bool DisplayManager::IsInMirrorMode() const {
return mirroring_display_id_ != gfx::Display::kInvalidDisplayID;
}
+bool DisplayManager::IsInUnifiedMode() const {
+ return multi_display_mode_ == UNIFIED &&
+ !software_mirroring_display_list_.empty();
+}
+
const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const {
DCHECK_NE(gfx::Display::kInvalidDisplayID, display_id);
@@ -879,6 +895,17 @@ const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const {
return iter->second;
}
+const gfx::Display DisplayManager::GetMirroringDisplayById(
+ int64 display_id) const {
+ auto iter = std::find_if(software_mirroring_display_list_.begin(),
+ software_mirroring_display_list_.end(),
+ [display_id](const gfx::Display& display) {
+ return display.id() == display_id;
+ });
+ return iter == software_mirroring_display_list_.end() ? gfx::Display()
+ : *iter;
+}
+
std::string DisplayManager::GetDisplayNameForId(int64 id) {
if (id == gfx::Display::kInvalidDisplayID)
return l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
@@ -899,30 +926,37 @@ int64 DisplayManager::GetDisplayIdForUIScaling() const {
return display_id;
}
-void DisplayManager::SetMirrorMode(bool mirrored) {
+void DisplayManager::SetMirrorMode(bool mirror) {
+#if defined(OS_CHROMEOS)
if (num_connected_displays() <= 1)
return;
-#if defined(OS_CHROMEOS)
if (base::SysInfo::IsRunningOnChromeOS()) {
ui::MultipleDisplayState new_state =
- mirrored ? ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR :
- ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
+ mirror ? ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR
+ : ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
Shell::GetInstance()->display_configurator()->SetDisplayMode(new_state);
return;
}
-#endif
+
// This is fallback path to emulate mirroroing on desktop.
- SetSecondDisplayMode(mirrored ? MIRRORING : EXTENDED);
DisplayInfoList display_info_list;
- int count = 0;
- for (std::map<int64, DisplayInfo>::const_iterator iter =
- display_info_.begin();
- count < 2; ++iter, ++count) {
- display_info_list.push_back(GetDisplayInfo(iter->second.id()));
+ for (DisplayList::const_iterator iter = active_display_list_.begin();
+ (display_info_list.size() < 2 && iter != active_display_list_.end());
+ ++iter) {
+ if (iter->id() == kUnifiedDisplayId)
+ continue;
+ display_info_list.push_back(GetDisplayInfo(iter->id()));
+ }
+ for (auto iter = software_mirroring_display_list_.begin();
+ (display_info_list.size() < 2 &&
+ iter != software_mirroring_display_list_.end());
+ ++iter) {
+ display_info_list.push_back(GetDisplayInfo(iter->id()));
}
+
+ SetSoftwareMirroring(mirror);
UpdateDisplays(display_info_list);
-#if defined(OS_CHROMEOS)
if (Shell::GetInstance()->display_configurator_animation()) {
Shell::GetInstance()->display_configurator_animation()->
StartFadeInAnimation();
@@ -934,7 +968,9 @@ void DisplayManager::AddRemoveDisplay() {
DCHECK(!active_display_list_.empty());
std::vector<DisplayInfo> new_display_info_list;
const DisplayInfo& first_display =
- GetDisplayInfo(active_display_list_[0].id());
+ IsInUnifiedMode()
+ ? GetDisplayInfo(software_mirroring_display_list_[0].id())
+ : GetDisplayInfo(active_display_list_[0].id());
new_display_info_list.push_back(first_display);
// Add if there is only one display connected.
if (num_connected_displays() == 1) {
@@ -946,7 +982,7 @@ void DisplayManager::AddRemoveDisplay() {
}
num_connected_displays_ = new_display_info_list.size();
mirroring_display_id_ = gfx::Display::kInvalidDisplayID;
- software_mirroring_display_ = gfx::Display();
+ software_mirroring_display_list_.clear();
UpdateDisplays(new_display_info_list);
}
@@ -966,7 +1002,7 @@ void DisplayManager::ToggleDisplayScaleFactor() {
#if defined(OS_CHROMEOS)
void DisplayManager::SetSoftwareMirroring(bool enabled) {
- SetSecondDisplayMode(enabled ? MIRRORING : EXTENDED);
+ SetMultiDisplayMode(enabled ? MIRRORING : default_multi_display_mode_);
}
bool DisplayManager::SoftwareMirroringEnabled() const {
@@ -974,10 +1010,17 @@ bool DisplayManager::SoftwareMirroringEnabled() const {
}
#endif
-void DisplayManager::SetSecondDisplayMode(SecondDisplayMode mode) {
- second_display_mode_ = mode;
+void DisplayManager::SetMultiDisplayMode(MultiDisplayMode mode) {
+ multi_display_mode_ = mode;
mirroring_display_id_ = gfx::Display::kInvalidDisplayID;
- software_mirroring_display_ = gfx::Display();
+ software_mirroring_display_list_.clear();
+}
+
+void DisplayManager::SetDefaultMultiDisplayMode(MultiDisplayMode mode) {
+ // TODO(oshima): Remove this constrain.
+ DCHECK_EQ(default_multi_display_mode_, EXTENDED);
+ DCHECK_EQ(mode, UNIFIED);
+ default_multi_display_mode_ = mode;
}
bool DisplayManager::UpdateDisplayBounds(int64 display_id,
@@ -1000,7 +1043,7 @@ void DisplayManager::CreateMirrorWindowAsyncIfAny() {
// Do not post a task if the software mirroring doesn't exist, or
// during initialization when compositor's init task isn't posted yet.
// ash::Shell::Init() will call this after the compositor is initialized.
- if (!software_mirroring_display_.is_valid() || !delegate_)
+ if (software_mirroring_display_list_.empty() || !delegate_)
return;
base::MessageLoopForUI::current()->PostTask(
FROM_HERE,
@@ -1043,23 +1086,54 @@ void DisplayManager::CreateSoftwareMirroringDisplay(
// the root window so that it matches the external display's
// resolution. This is necessary in order for scaling to work while
// mirrored.
- bool zero_is_source =
- first_display_id_ == (*display_info_list)[0].id() ||
- gfx::Display::InternalDisplayId() == (*display_info_list)[0].id();
- DCHECK_EQ(MIRRORING, second_display_mode_);
- mirroring_display_id_ = (*display_info_list)[zero_is_source ? 1 : 0].id();
- int64 display_id = mirroring_display_id_;
- auto iter = std::find_if(display_info_list->begin(), display_info_list->end(),
- [display_id](const DisplayInfo& info) {
- return info.id() == display_id;
- });
- DCHECK(iter != display_info_list->end());
- DisplayInfo info = *iter;
- info.SetOverscanInsets(gfx::Insets());
- InsertAndUpdateDisplayInfo(info);
- software_mirroring_display_ =
- CreateDisplayFromDisplayInfoById(mirroring_display_id_);
- display_info_list->erase(iter);
+ // int64 mirroring_display_id = gfx::Display::kInvalidDisplayID;
+ if (display_info_list->size() == 2) {
+ switch (multi_display_mode_) {
+ case MIRRORING: {
+ bool zero_is_source =
+ first_display_id_ == (*display_info_list)[0].id() ||
+ gfx::Display::InternalDisplayId() == (*display_info_list)[0].id();
+ DCHECK_EQ(MIRRORING, multi_display_mode_);
+ mirroring_display_id_ =
+ (*display_info_list)[zero_is_source ? 1 : 0].id();
+
+ int64 display_id = mirroring_display_id_;
+ auto iter =
+ std::find_if(display_info_list->begin(), display_info_list->end(),
+ [display_id](const DisplayInfo& info) {
+ return info.id() == display_id;
+ });
+ DCHECK(iter != display_info_list->end());
+
+ DisplayInfo info = *iter;
+ info.SetOverscanInsets(gfx::Insets());
+ InsertAndUpdateDisplayInfo(info);
+ software_mirroring_display_list_.push_back(
+ CreateDisplayFromDisplayInfoById(mirroring_display_id_));
+ display_info_list->erase(iter);
+ break;
+ }
+ case UNIFIED: {
+ // TODO(oshima): Suport displays that have different heights.
+ gfx::Rect unified_bounds;
+ software_mirroring_display_list_.clear();
+ for (auto& info : *display_info_list) {
+ InsertAndUpdateDisplayInfo(info);
+ software_mirroring_display_list_.push_back(
+ CreateDisplayFromDisplayInfoById(info.id()));
+ gfx::Point origin(unified_bounds.right(), 0);
+ unified_bounds.Union(gfx::Rect(origin, info.size_in_pixel()));
+ }
+ DisplayInfo info(kUnifiedDisplayId, "Unified Desktop", false);
+ info.SetBounds(unified_bounds);
+ display_info_list->clear();
+ display_info_list->push_back(info);
+ break;
+ }
+ case EXTENDED:
+ break;
+ }
+ }
}
gfx::Display* DisplayManager::FindDisplayForId(int64 id) {
@@ -1068,7 +1142,10 @@ gfx::Display* DisplayManager::FindDisplayForId(int64 id) {
[id](const gfx::Display& display) { return display.id() == id; });
if (iter != active_display_list_.end())
return &(*iter);
- DLOG(WARNING) << "Could not find display:" << id;
+ // TODO(oshima): This happens when a windows in unified desktop have
+ // been moved to normal window. Fix this.
+ if (id != kUnifiedDisplayId)
+ DLOG(WARNING) << "Could not find display:" << id;
return NULL;
}
@@ -1102,7 +1179,7 @@ void DisplayManager::OnDisplayInfoUpdated(const DisplayInfo& display_info) {
}
gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) {
- DCHECK(display_info_.find(id) != display_info_.end());
+ DCHECK(display_info_.find(id) != display_info_.end()) << "id=" << id;
const DisplayInfo& display_info = display_info_[id];
gfx::Display new_display(display_info.id());
@@ -1176,10 +1253,12 @@ bool DisplayManager::UpdateNonPrimaryDisplayBoundsForLayout(
}
void DisplayManager::CreateMirrorWindowIfAny() {
- if (software_mirroring_display_.is_valid() && delegate_) {
- DisplayInfo display_info = GetDisplayInfo(software_mirroring_display_.id());
- delegate_->CreateOrUpdateMirroringDisplay(display_info);
- }
+ if (software_mirroring_display_list_.empty() || !delegate_)
+ return;
+ DisplayInfoList list;
+ for (auto& display : software_mirroring_display_list_)
+ list.push_back(GetDisplayInfo(display.id()));
+ delegate_->CreateOrUpdateMirroringDisplay(list);
}
// static
@@ -1230,7 +1309,7 @@ void DisplayManager::UpdateDisplayBoundsForLayout(
}
void DisplayManager::RunPendingTasksForTest() {
- if (software_mirroring_display_.is_valid())
+ if (!software_mirroring_display_list_.empty())
base::RunLoop().RunUntilIdle();
}
diff --git a/ash/display/display_manager.h b/ash/display/display_manager.h
index a48fc67..3b0bd6a 100644
--- a/ash/display/display_manager.h
+++ b/ash/display/display_manager.h
@@ -39,6 +39,8 @@ class DisplayLayoutStore;
class MouseWarpController;
class ScreenAsh;
+typedef std::vector<DisplayInfo> DisplayInfoList;
+
namespace test {
class AshTestBase;
class DisplayManagerTestApi;
@@ -59,9 +61,9 @@ class ASH_EXPORT DisplayManager
public:
virtual ~Delegate() {}
- // Create or updates the mirroring window with |display_info|.
+ // Create or updates the mirroring window with |display_info_list|.
virtual void CreateOrUpdateMirroringDisplay(
- const DisplayInfo& display_info) = 0;
+ const DisplayInfoList& display_info_list) = 0;
// Closes the mirror window if exists.
virtual void CloseMirroringDisplay() = 0;
@@ -79,11 +81,16 @@ class ASH_EXPORT DisplayManager
// 1) EXTENDED mode extends the desktop to the second dislpay.
// 2) MIRRORING mode copies the content of the primary display to
// the 2nd display. (Software Mirroring).
- enum SecondDisplayMode {
+ // 3) UNIFIED mode creates single desktop across multiple displays.
+ enum MultiDisplayMode {
EXTENDED,
- MIRRORING
+ MIRRORING,
+ UNIFIED,
};
+ // The display ID for a virtual display assigned to a unified desktop.
+ static int64 kUnifiedDisplayId;
+
DisplayManager();
#if defined(OS_CHROMEOS)
~DisplayManager() override;
@@ -247,10 +254,11 @@ class ASH_EXPORT DisplayManager
bool IsInMirrorMode() const;
int64 mirroring_display_id() const { return mirroring_display_id_; }
- // Returns the display used for software mirrroring.
- const gfx::Display& software_mirroring_display() const {
- return software_mirroring_display_;
- }
+ bool IsInUnifiedMode() const;
+
+ // Returns the display used for software mirrroring. Returns invalid
+ // display if not found.
+ const gfx::Display GetMirroringDisplayById(int64 id) const;
// Retuns the display info associated with |display_id|.
const DisplayInfo& GetDisplayInfo(int64 display_id) const;
@@ -278,13 +286,17 @@ class ASH_EXPORT DisplayManager
bool SoftwareMirroringEnabled() const override;
#endif
bool software_mirroring_enabled() const {
- return second_display_mode_ == MIRRORING;
+ return multi_display_mode_ == MIRRORING;
};
- // Sets/gets second display mode.
- void SetSecondDisplayMode(SecondDisplayMode mode);
- SecondDisplayMode second_display_mode() const {
- return second_display_mode_;
+ // Sets/gets multi display mode.
+ void SetMultiDisplayMode(MultiDisplayMode mode);
+ MultiDisplayMode multi_display_mode() const { return multi_display_mode_; }
+
+ // Sets/gets default multi display mode.
+ void SetDefaultMultiDisplayMode(MultiDisplayMode mode);
+ MultiDisplayMode default_multi_display_mode() const {
+ return default_multi_display_mode_;
}
// Update the bounds of the display given by |display_id|.
@@ -397,9 +409,11 @@ private:
// on device as well as during the unit tests.
bool change_display_upon_host_resize_;
- SecondDisplayMode second_display_mode_;
+ MultiDisplayMode multi_display_mode_;
+ MultiDisplayMode default_multi_display_mode_;
+
int64 mirroring_display_id_;
- gfx::Display software_mirroring_display_;
+ DisplayList software_mirroring_display_list_;
// User preference for rotation lock of the internal display.
bool registered_internal_display_rotation_lock_;
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index 9ed1039..00e2f10 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -121,8 +121,12 @@ class DisplayManagerTest : public test::AshTestBase,
// aura::WindowObserver overrides:
void OnWindowDestroying(aura::Window* window) override {
- ASSERT_EQ(Shell::GetPrimaryRootWindow(), window);
- root_window_destroyed_ = true;
+ // TODO(oshima): When moving between unified desktop, the
+ // primary root window can be deleted.
+ if (!display_manager()->IsInUnifiedMode()) {
+ ASSERT_EQ(Shell::GetPrimaryRootWindow(), window);
+ root_window_destroyed_ = true;
+ }
}
private:
@@ -1207,7 +1211,7 @@ TEST_F(DisplayManagerTest, SoftwareMirroring) {
Shell::GetScreen()->AddObserver(&display_observer);
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
- display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
+ display_manager->SetMultiDisplayMode(DisplayManager::MIRRORING);
display_manager->UpdateDisplays();
RunAllPendingInMessageLoop();
EXPECT_TRUE(display_observer.changed_and_reset());
@@ -1265,7 +1269,7 @@ TEST_F(DisplayManagerTest, SingleDisplayToSoftwareMirroring) {
UpdateDisplay("600x400");
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
- display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
+ display_manager->SetMultiDisplayMode(DisplayManager::MIRRORING);
UpdateDisplay("600x400,600x400");
EXPECT_TRUE(display_manager->IsInMirrorMode());
@@ -1458,6 +1462,34 @@ TEST_F(DisplayManagerTest, MAYBE_UpdateDisplayWithHostOrigin) {
EXPECT_EQ("200x300", host1->GetBounds().size().ToString());
}
+#if !defined(OS_WIN) && defined(USE_X11)
+
+TEST_F(DisplayManagerTest, UnifiedDesktopBasic) {
+ display_manager()->SetDefaultMultiDisplayMode(DisplayManager::UNIFIED);
+ display_manager()->SetMultiDisplayMode(DisplayManager::UNIFIED);
+ UpdateDisplay("300x200,400x500");
+
+ gfx::Screen* screen =
+ gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_ALTERNATE);
+ EXPECT_EQ("700x500", screen->GetPrimaryDisplay().size().ToString());
+
+ display_manager()->SetMirrorMode(true);
+ EXPECT_EQ("300x200", screen->GetPrimaryDisplay().size().ToString());
+
+ display_manager()->SetMirrorMode(false);
+ EXPECT_EQ("700x500", screen->GetPrimaryDisplay().size().ToString());
+
+ // Swithc to single desktop.
+ UpdateDisplay("500x300");
+ EXPECT_EQ("500x300", screen->GetPrimaryDisplay().size().ToString());
+
+ // Swithc to unified desktop.
+ UpdateDisplay("500x300,400x500");
+ EXPECT_EQ("900x500", screen->GetPrimaryDisplay().size().ToString());
+}
+
+#endif
+
class ScreenShutdownTest : public test::AshTestBase {
public:
ScreenShutdownTest() {
diff --git a/ash/display/mirror_window_controller.cc b/ash/display/mirror_window_controller.cc
index c7e5acf..8fb7767 100644
--- a/ash/display/mirror_window_controller.cc
+++ b/ash/display/mirror_window_controller.cc
@@ -76,6 +76,11 @@ class NoneCaptureClient : public aura::client::CaptureClient {
} // namespace
+MirrorWindowController::MirroringHostInfo::MirroringHostInfo() {
+}
+MirrorWindowController::MirroringHostInfo::~MirroringHostInfo() {
+}
+
MirrorWindowController::MirrorWindowController() {}
MirrorWindowController::~MirrorWindowController() {
@@ -83,93 +88,187 @@ MirrorWindowController::~MirrorWindowController() {
Close();
}
-void MirrorWindowController::UpdateWindow(const DisplayInfo& display_info) {
+void MirrorWindowController::UpdateWindow(
+ const std::vector<DisplayInfo>& display_info_list) {
static int mirror_host_count = 0;
- if (!ash_host_.get()) {
- AshWindowTreeHostInitParams init_params;
- init_params.initial_bounds = display_info.bounds_in_native();
- ash_host_.reset(AshWindowTreeHost::Create(init_params));
- aura::WindowTreeHost* host = ash_host_->AsWindowTreeHost();
- host->window()->SetName(
- base::StringPrintf("MirrorRootWindow-%d", mirror_host_count++));
- host->compositor()->SetBackgroundColor(SK_ColorBLACK);
- // No need to remove the observer because the DisplayController outlives the
- // host.
- host->AddObserver(Shell::GetInstance()->display_controller());
- host->AddObserver(this);
- // TODO(oshima): TouchHUD is using idkey.
- InitRootWindowSettings(host->window())->display_id = display_info.id();
- host->InitHost();
+ DisplayManager* display_manager = Shell::GetInstance()->display_manager();
+ const gfx::Display& primary = Shell::GetScreen()->GetPrimaryDisplay();
+ const DisplayInfo& source_display_info =
+ display_manager->GetDisplayInfo(primary.id());
+
+ gfx::Point mirroring_origin;
+ for (const DisplayInfo& display_info : display_info_list) {
+ if (mirroring_host_info_map_.find(display_info.id()) ==
+ mirroring_host_info_map_.end()) {
+ AshWindowTreeHostInitParams init_params;
+ init_params.initial_bounds = display_info.bounds_in_native();
+ MirroringHostInfo* host_info = new MirroringHostInfo;
+ host_info->ash_host.reset(AshWindowTreeHost::Create(init_params));
+ mirroring_host_info_map_[display_info.id()] = host_info;
+
+ aura::WindowTreeHost* host = host_info->ash_host->AsWindowTreeHost();
+ host->window()->SetName(
+ base::StringPrintf("MirrorRootWindow-%d", mirror_host_count++));
+ host->compositor()->SetBackgroundColor(SK_ColorBLACK);
+ // No need to remove the observer because the DisplayController outlives
+ // the
+ // host.
+ host->AddObserver(Shell::GetInstance()->display_controller());
+ host->AddObserver(this);
+ // TODO(oshima): TouchHUD is using idkey.
+ InitRootWindowSettings(host->window())->display_id = display_info.id();
+ host->InitHost();
#if defined(USE_X11)
- DisableInput(host->GetAcceleratedWidget());
+ if (display_manager->multi_display_mode() != DisplayManager::UNIFIED)
+ DisableInput(host->GetAcceleratedWidget());
+#endif
+
+#if defined(OS_CHROMEOS)
+ if (display_manager->multi_display_mode() == DisplayManager::UNIFIED) {
+ host_info->ash_host->ConfineCursorToRootWindow();
+ AshWindowTreeHost* unified_ash_host =
+ Shell::GetInstance()
+ ->display_controller()
+ ->GetAshWindowTreeHostForDisplayId(
+ Shell::GetScreen()->GetPrimaryDisplay().id());
+ unified_ash_host->RegisterMirroringHost(host_info->ash_host.get());
+ }
#endif
- aura::client::SetCaptureClient(host->window(), new NoneCaptureClient());
- host->Show();
-
- // TODO(oshima): Start mirroring.
- aura::Window* mirror_window = new aura::Window(NULL);
- mirror_window->Init(ui::LAYER_SOLID_COLOR);
- host->window()->AddChild(mirror_window);
- mirror_window->SetBounds(host->window()->bounds());
- mirror_window->Show();
- reflector_ = aura::Env::GetInstance()->context_factory()->CreateReflector(
- Shell::GetPrimaryRootWindow()->GetHost()->compositor(),
- mirror_window->layer());
- } else {
- aura::WindowTreeHost* host = ash_host_->AsWindowTreeHost();
- GetRootWindowSettings(host->window())->display_id = display_info.id();
- host->SetBounds(display_info.bounds_in_native());
+ aura::client::SetCaptureClient(host->window(), new NoneCaptureClient());
+ host->Show();
+
+ aura::Window* mirror_window = host_info->mirror_window =
+ new aura::Window(nullptr);
+ mirror_window->Init(ui::LAYER_SOLID_COLOR);
+ host->window()->AddChild(mirror_window);
+ mirror_window->SetBounds(host->window()->bounds());
+ mirror_window->Show();
+ if (reflector_) {
+ // TODO(oshima): Enable this once reflect change is landed.
+ // reflector_->AddMirroringLayer(mirror_window->layer());
+ } else {
+ reflector_ =
+ aura::Env::GetInstance()->context_factory()->CreateReflector(
+ Shell::GetPrimaryRootWindow()->GetHost()->compositor(),
+ mirror_window->layer());
+ }
+ } else {
+ aura::WindowTreeHost* host = mirroring_host_info_map_[display_info.id()]
+ ->ash_host->AsWindowTreeHost();
+ GetRootWindowSettings(host->window())->display_id = display_info.id();
+ host->SetBounds(display_info.bounds_in_native());
+ }
+
+ AshWindowTreeHost* mirroring_ash_host =
+ mirroring_host_info_map_[display_info.id()]->ash_host.get();
+ switch (display_manager->multi_display_mode()) {
+ case DisplayManager::MIRRORING: {
+ scoped_ptr<RootWindowTransformer> transformer(
+ CreateRootWindowTransformerForMirroredDisplay(source_display_info,
+ display_info));
+ mirroring_ash_host->SetRootWindowTransformer(transformer.Pass());
+ break;
+ }
+ case DisplayManager::UNIFIED: {
+ gfx::Display display;
+ display.SetScaleAndBounds(
+ 1.0f, gfx::Rect(mirroring_origin,
+ display_info.bounds_in_native().size()));
+ mirroring_origin.SetPoint(display.bounds().right(), 0);
+ scoped_ptr<RootWindowTransformer> transformer(
+ CreateRootWindowTransformerForUnifiedDesktop(primary.bounds(),
+ display));
+ mirroring_ash_host->SetRootWindowTransformer(transformer.Pass());
+ break;
+ }
+ case DisplayManager::EXTENDED:
+ NOTREACHED();
+ }
}
- DisplayManager* display_manager = Shell::GetInstance()->display_manager();
- const DisplayInfo& source_display_info = display_manager->GetDisplayInfo(
- Shell::GetScreen()->GetPrimaryDisplay().id());
- DCHECK(display_manager->IsInMirrorMode());
- scoped_ptr<RootWindowTransformer> transformer(
- CreateRootWindowTransformerForMirroredDisplay(source_display_info,
- display_info));
- ash_host_->SetRootWindowTransformer(transformer.Pass());
+ // Deleting WTHs for disconnected displays.
+ if (mirroring_host_info_map_.size() > display_info_list.size()) {
+ for (MirroringHostInfoMap::iterator iter = mirroring_host_info_map_.begin();
+ iter != mirroring_host_info_map_.end();) {
+ if (std::find_if(display_info_list.begin(), display_info_list.end(),
+ [iter](const DisplayInfo& info) {
+ return info.id() == iter->first;
+ }) == display_info_list.end()) {
+ CloseAndDeleteHost(iter->second);
+ iter = mirroring_host_info_map_.erase(iter);
+ } else {
+ ++iter;
+ }
+ }
+ }
}
void MirrorWindowController::UpdateWindow() {
- if (ash_host_.get()) {
- DisplayManager* display_manager = Shell::GetInstance()->display_manager();
- const DisplayInfo& mirror_display_info = display_manager->GetDisplayInfo(
- display_manager->mirroring_display_id());
- UpdateWindow(mirror_display_info);
- }
+ if (!mirroring_host_info_map_.size())
+ return;
+ DisplayManager* display_manager = Shell::GetInstance()->display_manager();
+ std::vector<DisplayInfo> display_info_list;
+ for (auto& pair : mirroring_host_info_map_)
+ display_info_list.push_back(display_manager->GetDisplayInfo(pair.first));
+ UpdateWindow(display_info_list);
}
void MirrorWindowController::Close() {
- if (ash_host_.get()) {
- aura::WindowTreeHost* host = ash_host_->AsWindowTreeHost();
+ for (auto& info : mirroring_host_info_map_) {
+ CloseAndDeleteHost(info.second);
+ }
+ mirroring_host_info_map_.clear();
+ if (reflector_) {
aura::Env::GetInstance()->context_factory()->RemoveReflector(
reflector_.get());
- reflector_ = nullptr;
- NoneCaptureClient* capture_client = static_cast<NoneCaptureClient*>(
- aura::client::GetCaptureClient(host->window()));
- aura::client::SetCaptureClient(host->window(), NULL);
- delete capture_client;
-
- host->RemoveObserver(Shell::GetInstance()->display_controller());
- host->RemoveObserver(this);
- ash_host_.reset();
+ reflector_.reset();
}
}
void MirrorWindowController::OnHostResized(const aura::WindowTreeHost* host) {
- if (mirror_window_host_size_ == host->GetBounds().size())
- return;
- mirror_window_host_size_ = host->GetBounds().size();
- reflector_->OnMirroringCompositorResized();
- ash_host_->SetRootWindowTransformer(CreateRootWindowTransformer().Pass());
- Shell::GetInstance()->display_controller()->cursor_window_controller()->
- UpdateLocation();
+ for (auto& pair : mirroring_host_info_map_) {
+ MirroringHostInfo* info = pair.second;
+ if (info->ash_host->AsWindowTreeHost() == host) {
+ if (info->mirror_window_host_size == host->GetBounds().size())
+ return;
+ info->mirror_window_host_size = host->GetBounds().size();
+ reflector_->OnMirroringCompositorResized();
+ info->ash_host->SetRootWindowTransformer(
+ CreateRootWindowTransformer().Pass());
+ Shell::GetInstance()
+ ->display_controller()
+ ->cursor_window_controller()
+ ->UpdateLocation();
+ return;
+ }
+ }
}
aura::Window* MirrorWindowController::GetWindow() {
- return ash_host_.get() ? ash_host_->AsWindowTreeHost()->window() : NULL;
+ DisplayManager* display_manager = Shell::GetInstance()->display_manager();
+ if (display_manager->multi_display_mode() != DisplayManager::MIRRORING ||
+ mirroring_host_info_map_.empty()) {
+ return nullptr;
+ }
+
+ DCHECK_EQ(1U, mirroring_host_info_map_.size());
+ return mirroring_host_info_map_.begin()
+ ->second->ash_host->AsWindowTreeHost()
+ ->window();
+}
+
+void MirrorWindowController::CloseAndDeleteHost(MirroringHostInfo* host_info) {
+ aura::WindowTreeHost* host = host_info->ash_host->AsWindowTreeHost();
+ NoneCaptureClient* capture_client = static_cast<NoneCaptureClient*>(
+ aura::client::GetCaptureClient(host->window()));
+ aura::client::SetCaptureClient(host->window(), NULL);
+ delete capture_client;
+
+ host->RemoveObserver(Shell::GetInstance()->display_controller());
+ host->RemoveObserver(this);
+ // reflector_->RemoveMirroringLayer(host_info->mirror_window->layer());
+ delete host_info;
}
scoped_ptr<RootWindowTransformer>
diff --git a/ash/display/mirror_window_controller.h b/ash/display/mirror_window_controller.h
index 5b24cc6..39adef5 100644
--- a/ash/display/mirror_window_controller.h
+++ b/ash/display/mirror_window_controller.h
@@ -5,6 +5,9 @@
#ifndef ASH_DISPLAY_MIRROR_WINDOW_CONTROLLER_H_
#define ASH_DISPLAY_MIRROR_WINDOW_CONTROLLER_H_
+#include <map>
+#include <vector>
+
#include "ash/ash_export.h"
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
@@ -40,7 +43,7 @@ class ASH_EXPORT MirrorWindowController : public aura::WindowTreeHostObserver {
// Updates the root window's bounds using |display_info|.
// Creates the new root window if one doesn't exist.
- void UpdateWindow(const DisplayInfo& display_info);
+ void UpdateWindow(const std::vector<DisplayInfo>& display_info);
// Same as above, but using existing display info
// for the mirrored display.
@@ -59,12 +62,23 @@ class ASH_EXPORT MirrorWindowController : public aura::WindowTreeHostObserver {
private:
friend class test::MirrorWindowTestApi;
+ struct MirroringHostInfo {
+ MirroringHostInfo();
+ ~MirroringHostInfo();
+ scoped_ptr<AshWindowTreeHost> ash_host;
+ gfx::Size mirror_window_host_size;
+ aura::Window* mirror_window = nullptr;
+ };
+
+ void CloseAndDeleteHost(MirroringHostInfo* host_info);
+
// Creates a RootWindowTransformer for current display
// configuration.
scoped_ptr<RootWindowTransformer> CreateRootWindowTransformer() const;
- scoped_ptr<AshWindowTreeHost> ash_host_;
- gfx::Size mirror_window_host_size_;
+ typedef std::map<int64_t, MirroringHostInfo*> MirroringHostInfoMap;
+ MirroringHostInfoMap mirroring_host_info_map_;
+
scoped_ptr<ui::Reflector> reflector_;
DISALLOW_COPY_AND_ASSIGN(MirrorWindowController);
diff --git a/ash/display/mirror_window_controller_unittest.cc b/ash/display/mirror_window_controller_unittest.cc
index c1fe0cb..822f4f8 100644
--- a/ash/display/mirror_window_controller_unittest.cc
+++ b/ash/display/mirror_window_controller_unittest.cc
@@ -77,7 +77,7 @@ TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursorBasic) {
test_window_delegate.set_window_component(HTTOP);
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
- display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
+ display_manager->SetMultiDisplayMode(DisplayManager::MIRRORING);
UpdateDisplay("400x400,400x400");
aura::Window* root = Shell::GetInstance()->GetPrimaryRootWindow();
scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithDelegate(
@@ -127,7 +127,7 @@ TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursorRotate) {
test_window_delegate.set_window_component(HTTOP);
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
- display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
+ display_manager->SetMultiDisplayMode(DisplayManager::MIRRORING);
UpdateDisplay("400x400,400x400");
aura::Window* root = Shell::GetInstance()->GetPrimaryRootWindow();
scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithDelegate(
@@ -182,7 +182,7 @@ TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursorRotate) {
TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursorLocations) {
test::MirrorWindowTestApi test_api;
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
- display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
+ display_manager->SetMultiDisplayMode(DisplayManager::MIRRORING);
// Test with device scale factor.
UpdateDisplay("400x600*2,400x600");
@@ -236,7 +236,7 @@ TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursorMoveOnEnter) {
EXPECT_EQ(1.0f, cursor_test_api.GetCurrentCursor().device_scale_factor());
EXPECT_EQ(gfx::Display::ROTATE_0, cursor_test_api.GetCurrentCursorRotation());
- display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
+ display_manager->SetMultiDisplayMode(DisplayManager::MIRRORING);
UpdateDisplay("400x400*2/r,400x400");
// Entering mirror mode should have centered the cursor on the primary display
@@ -271,7 +271,7 @@ TEST_F(MirrorWindowControllerTest, MAYBE_DockMode) {
CreateDisplayInfo(external_id, gfx::Rect(1, 1, 100, 100));
std::vector<DisplayInfo> display_info_list;
- display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
+ display_manager->SetMultiDisplayMode(DisplayManager::MIRRORING);
// software mirroring.
display_info_list.push_back(internal_display_info);
@@ -289,7 +289,7 @@ TEST_F(MirrorWindowControllerTest, MAYBE_DockMode) {
// dock mode.
display_info_list.clear();
display_info_list.push_back(external_display_info);
- display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
+ display_manager->SetMultiDisplayMode(DisplayManager::MIRRORING);
display_manager->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(1U, display_manager->GetNumDisplays());
EXPECT_FALSE(display_manager->IsInMirrorMode());
@@ -298,7 +298,7 @@ TEST_F(MirrorWindowControllerTest, MAYBE_DockMode) {
display_info_list.clear();
display_info_list.push_back(internal_display_info);
display_info_list.push_back(external_display_info);
- display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
+ display_manager->SetMultiDisplayMode(DisplayManager::MIRRORING);
display_manager->OnNativeDisplaysChanged(display_info_list);
EXPECT_EQ(1U, display_manager->GetNumDisplays());
EXPECT_TRUE(display_manager->IsInMirrorMode());
diff --git a/ash/display/root_window_transformers.cc b/ash/display/root_window_transformers.cc
index 8a028b3..6a9eea3 100644
--- a/ash/display/root_window_transformers.cc
+++ b/ash/display/root_window_transformers.cc
@@ -275,6 +275,37 @@ class MirrorRootWindowTransformer : public RootWindowTransformer {
DISALLOW_COPY_AND_ASSIGN(MirrorRootWindowTransformer);
};
+class PartialBoundsRootWindowTransformer : public RootWindowTransformer {
+ public:
+ PartialBoundsRootWindowTransformer(const gfx::Rect& screen_bounds,
+ const gfx::Display& display) {
+ gfx::SizeF root_size(display.bounds().size());
+ root_size.Scale(display.device_scale_factor());
+ root_bounds_ = gfx::Rect(gfx::ToFlooredSize(root_size));
+
+ transform_.Translate(-SkIntToMScalar(display.bounds().x()),
+ -SkIntToMScalar(display.bounds().y()));
+ }
+
+ // RootWindowTransformer:
+ gfx::Transform GetTransform() const override { return transform_; }
+ gfx::Transform GetInverseTransform() const override {
+ gfx::Transform invert;
+ CHECK(transform_.GetInverse(&invert));
+ return invert;
+ }
+ gfx::Rect GetRootWindowBounds(const gfx::Size& host_size) const override {
+ return root_bounds_;
+ }
+ gfx::Insets GetHostInsets() const override { return gfx::Insets(); }
+
+ private:
+ gfx::Transform transform_;
+ gfx::Rect root_bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(PartialBoundsRootWindowTransformer);
+};
+
} // namespace
RootWindowTransformer* CreateRootWindowTransformerForDisplay(
@@ -290,4 +321,10 @@ RootWindowTransformer* CreateRootWindowTransformerForMirroredDisplay(
mirror_display_info);
}
+RootWindowTransformer* CreateRootWindowTransformerForUnifiedDesktop(
+ const gfx::Rect& screen_bounds,
+ const gfx::Display& display) {
+ return new PartialBoundsRootWindowTransformer(screen_bounds, display);
+}
+
} // namespace ash
diff --git a/ash/display/root_window_transformers.h b/ash/display/root_window_transformers.h
index b41ccdf..61ccea7 100644
--- a/ash/display/root_window_transformers.h
+++ b/ash/display/root_window_transformers.h
@@ -13,6 +13,7 @@ class Window;
namespace gfx {
class Display;
+class Rect;
class Transform;
}
@@ -32,6 +33,13 @@ ASH_EXPORT RootWindowTransformer* CreateRootWindowTransformerForMirroredDisplay(
const DisplayInfo& source_display_info,
const DisplayInfo& mirror_display_info);
+// Creates a RootWindowTransformers for unified desktop mode.
+// |screen_bounds| specifies the unified desktop's bounds and
+// |display| specifies the display used to mirror the unified desktop.
+ASH_EXPORT RootWindowTransformer* CreateRootWindowTransformerForUnifiedDesktop(
+ const gfx::Rect& screen_bounds,
+ const gfx::Display& display);
+
} // namespace ash
#endif // ASH_DISPLAY_ROOT_WINDOW_TRANSFORMERS_H_
diff --git a/ash/display/root_window_transformers_unittest.cc b/ash/display/root_window_transformers_unittest.cc
index 6639ec9..1036b31 100644
--- a/ash/display/root_window_transformers_unittest.cc
+++ b/ash/display/root_window_transformers_unittest.cc
@@ -393,7 +393,7 @@ TEST_F(RootWindowTransformersTest, LetterBoxPillarBox) {
return;
test::MirrorWindowTestApi test_api;
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
- display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
+ display_manager->SetMultiDisplayMode(DisplayManager::MIRRORING);
UpdateDisplay("400x200,500x500");
scoped_ptr<RootWindowTransformer> transformer(
test_api.CreateCurrentRootWindowTransformer());
diff --git a/ash/display/screen_ash.cc b/ash/display/screen_ash.cc
index 700abe6..5941bcc 100644
--- a/ash/display/screen_ash.cc
+++ b/ash/display/screen_ash.cc
@@ -165,8 +165,9 @@ gfx::Display ScreenAsh::GetDisplayNearestWindow(gfx::NativeView window) const {
DisplayManager* display_manager = GetDisplayManager();
// RootWindow needs Display to determine its device scale factor
// for non desktop display.
- if (display_manager->software_mirroring_display().id() == id)
- return display_manager->software_mirroring_display();
+ gfx::Display mirroring_display = display_manager->GetMirroringDisplayById(id);
+ if (mirroring_display.is_valid())
+ return mirroring_display;
return display_manager->GetDisplayForId(id);
}
diff --git a/ash/host/ash_window_tree_host.h b/ash/host/ash_window_tree_host.h
index 321ee25..fab7afd 100644
--- a/ash/host/ash_window_tree_host.h
+++ b/ash/host/ash_window_tree_host.h
@@ -55,6 +55,8 @@ class ASH_EXPORT AshWindowTreeHost {
// Stop listening for events in preparation for shutdown.
virtual void PrepareForShutdown() {}
+ virtual void RegisterMirroringHost(AshWindowTreeHost* mirroring_ash_host) {}
+
protected:
// Translates the native mouse location into screen coordinates.
void TranslateLocatedEvent(ui::LocatedEvent* event);
diff --git a/ash/host/ash_window_tree_host_init_params.cc b/ash/host/ash_window_tree_host_init_params.cc
index 55d15c0..ae1f58e 100644
--- a/ash/host/ash_window_tree_host_init_params.cc
+++ b/ash/host/ash_window_tree_host_init_params.cc
@@ -6,11 +6,13 @@
namespace ash {
+AshWindowTreeHostInitParams::AshWindowTreeHostInitParams()
+ : offscreen(false)
#if defined(OS_WIN)
-AshWindowTreeHostInitParams::AshWindowTreeHostInitParams() : remote_hwnd(NULL) {
-#else
-AshWindowTreeHostInitParams::AshWindowTreeHostInitParams() {
+ ,
+ remote_hwnd(NULL)
#endif
+{
}
AshWindowTreeHostInitParams::~AshWindowTreeHostInitParams() {
diff --git a/ash/host/ash_window_tree_host_init_params.h b/ash/host/ash_window_tree_host_init_params.h
index d9bb7de..bc584d8 100644
--- a/ash/host/ash_window_tree_host_init_params.h
+++ b/ash/host/ash_window_tree_host_init_params.h
@@ -22,6 +22,8 @@ struct ASH_EXPORT AshWindowTreeHostInitParams {
gfx::Rect initial_bounds;
+ bool offscreen;
+
#if defined(OS_WIN)
HWND remote_hwnd;
#endif
diff --git a/ash/host/ash_window_tree_host_ozone.cc b/ash/host/ash_window_tree_host_ozone.cc
index cb2ec66..e45bf5d 100644
--- a/ash/host/ash_window_tree_host_ozone.cc
+++ b/ash/host/ash_window_tree_host_ozone.cc
@@ -5,6 +5,7 @@
#include "ash/host/ash_window_tree_host.h"
#include "ash/host/ash_window_tree_host_init_params.h"
+#include "ash/host/ash_window_tree_host_unified.h"
#include "ash/host/root_window_transformer.h"
#include "ash/host/transformer_helper.h"
#include "base/command_line.h"
@@ -144,6 +145,8 @@ void AshWindowTreeHostOzone::SetTapToClickPaused(bool state) {
AshWindowTreeHost* AshWindowTreeHost::Create(
const AshWindowTreeHostInitParams& init_params) {
+ if (init_params.offscreen)
+ return new AshWindowTreeHostUnified(init_params.initial_bounds);
return new AshWindowTreeHostOzone(init_params.initial_bounds);
}
diff --git a/ash/host/ash_window_tree_host_unified.cc b/ash/host/ash_window_tree_host_unified.cc
new file mode 100644
index 0000000..4317365
--- /dev/null
+++ b/ash/host/ash_window_tree_host_unified.cc
@@ -0,0 +1,164 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/host/ash_window_tree_host_unified.h"
+#include "ash/host/root_window_transformer.h"
+#include "base/logging.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_targeter.h"
+#include "ui/compositor/compositor.h"
+#include "ui/events/event_processor.h"
+#include "ui/gfx/geometry/insets.h"
+
+namespace ash {
+
+class UnifiedEventTargeter : public aura::WindowTargeter {
+ public:
+ UnifiedEventTargeter(aura::Window* src_root, aura::Window* dst_root)
+ : src_root_(src_root), dst_root_(dst_root) {}
+
+ ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
+ ui::Event* event) override {
+ if (root == src_root_ && !event->target()) {
+ if (event->IsLocatedEvent()) {
+ ui::LocatedEvent* located_event = static_cast<ui::LocatedEvent*>(event);
+ located_event->ConvertLocationToTarget(
+ static_cast<aura::Window*>(nullptr), dst_root_);
+ located_event->UpdateForRootTransform(
+ dst_root_->GetHost()->GetRootTransform());
+ }
+ ignore_result(
+ dst_root_->GetHost()->event_processor()->OnEventFromSource(event));
+ return nullptr;
+ } else {
+ LOG(ERROR) << "Handling Event:" << event->type();
+ return aura::WindowTargeter::FindTargetForEvent(root, event);
+ }
+ }
+
+ aura::Window* src_root_;
+ aura::Window* dst_root_;
+
+ DISALLOW_COPY_AND_ASSIGN(UnifiedEventTargeter);
+};
+
+AshWindowTreeHostUnified::AshWindowTreeHostUnified(
+ const gfx::Rect& initial_bounds)
+ : bounds_(gfx::Rect(initial_bounds.size())) {
+ CreateCompositor(GetAcceleratedWidget());
+}
+
+AshWindowTreeHostUnified::~AshWindowTreeHostUnified() {
+ DestroyCompositor();
+ DestroyDispatcher();
+}
+
+void AshWindowTreeHostUnified::PrepareForShutdown() {
+ for (auto host : mirroring_hosts_)
+ host->PrepareForShutdown();
+}
+
+void AshWindowTreeHostUnified::RegisterMirroringHost(
+ AshWindowTreeHost* mirroring_ash_host) {
+ aura::Window* src_root = mirroring_ash_host->AsWindowTreeHost()->window();
+ src_root->SetEventTargeter(
+ make_scoped_ptr(new UnifiedEventTargeter(src_root, window())));
+ DCHECK(std::find(mirroring_hosts_.begin(), mirroring_hosts_.end(),
+ mirroring_ash_host) == mirroring_hosts_.end());
+ mirroring_hosts_.push_back(mirroring_ash_host);
+ mirroring_ash_host->AsWindowTreeHost()->window()->AddObserver(this);
+}
+
+void AshWindowTreeHostUnified::ToggleFullScreen() {
+}
+
+bool AshWindowTreeHostUnified::ConfineCursorToRootWindow() {
+ return true;
+}
+
+void AshWindowTreeHostUnified::UnConfineCursor() {
+}
+
+void AshWindowTreeHostUnified::SetRootWindowTransformer(
+ scoped_ptr<RootWindowTransformer> transformer) {
+ // TODO(oshima): Find out if this is neceessary.
+ NOTIMPLEMENTED();
+}
+
+gfx::Insets AshWindowTreeHostUnified::GetHostInsets() const {
+ return gfx::Insets();
+}
+
+aura::WindowTreeHost* AshWindowTreeHostUnified::AsWindowTreeHost() {
+ return this;
+}
+
+ui::EventSource* AshWindowTreeHostUnified::GetEventSource() {
+ return this;
+}
+
+gfx::AcceleratedWidget AshWindowTreeHostUnified::GetAcceleratedWidget() {
+ // TODO(oshima): Enable offscreen compositor.
+ return gfx::kNullAcceleratedWidget;
+}
+
+void AshWindowTreeHostUnified::Show() {
+}
+
+void AshWindowTreeHostUnified::Hide() {
+}
+
+gfx::Rect AshWindowTreeHostUnified::GetBounds() const {
+ return bounds_;
+}
+
+void AshWindowTreeHostUnified::SetBounds(const gfx::Rect& bounds) {
+ if (bounds_.size() == bounds.size())
+ return;
+ bounds_.set_size(bounds.size());
+ OnHostResized(bounds_.size());
+}
+
+void AshWindowTreeHostUnified::SetCapture() {
+}
+
+void AshWindowTreeHostUnified::ReleaseCapture() {
+}
+
+gfx::Point AshWindowTreeHostUnified::GetLocationOnNativeScreen() const {
+ return gfx::Point();
+}
+
+void AshWindowTreeHostUnified::SetCursorNative(gfx::NativeCursor cursor) {
+ for (auto host : mirroring_hosts_)
+ host->AsWindowTreeHost()->SetCursor(cursor);
+}
+
+void AshWindowTreeHostUnified::MoveCursorToNative(const gfx::Point& location) {
+ // TODO(oshima): Find out if this is neceessary.
+ NOTIMPLEMENTED();
+}
+
+void AshWindowTreeHostUnified::OnCursorVisibilityChangedNative(bool show) {
+ for (auto host : mirroring_hosts_)
+ host->AsWindowTreeHost()->OnCursorVisibilityChanged(show);
+}
+
+void AshWindowTreeHostUnified::OnWindowDestroying(aura::Window* window) {
+ auto iter =
+ std::find_if(mirroring_hosts_.begin(), mirroring_hosts_.end(),
+ [window](AshWindowTreeHost* ash_host) {
+ return ash_host->AsWindowTreeHost()->window() == window;
+ });
+ DCHECK(iter != mirroring_hosts_.end());
+ window->RemoveObserver(this);
+ mirroring_hosts_.erase(iter);
+}
+
+ui::EventProcessor* AshWindowTreeHostUnified::GetEventProcessor() {
+ return dispatcher();
+}
+
+} // namespace ash
diff --git a/ash/host/ash_window_tree_host_unified.h b/ash/host/ash_window_tree_host_unified.h
new file mode 100644
index 0000000..024b8df
--- /dev/null
+++ b/ash/host/ash_window_tree_host_unified.h
@@ -0,0 +1,75 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_HOST_ASH_WINDOW_TREE_HOST_UNIFIED_H_
+#define ASH_HOST_ASH_WINDOW_TREE_HOST_UNIFIED_H_
+
+#include <vector>
+
+#include "ash/host/ash_window_tree_host.h"
+#include "ui/aura/window_observer.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/events/event_source.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace ui {
+class Reflector;
+}
+
+namespace ash {
+class DisplayInfo;
+
+// A WTH used for unified desktop mode. This creates an offscreen
+// compositor whose texture will be copied into each displays'
+// compositor.
+class AshWindowTreeHostUnified : public AshWindowTreeHost,
+ public aura::WindowTreeHost,
+ public aura::WindowObserver,
+ public ui::EventSource {
+ public:
+ explicit AshWindowTreeHostUnified(const gfx::Rect& initial_bounds);
+ ~AshWindowTreeHostUnified() override;
+
+ private:
+ // AshWindowTreeHost:
+ void ToggleFullScreen() override;
+ bool ConfineCursorToRootWindow() override;
+ void UnConfineCursor() override;
+ void SetRootWindowTransformer(
+ scoped_ptr<RootWindowTransformer> transformer) override;
+ gfx::Insets GetHostInsets() const override;
+ aura::WindowTreeHost* AsWindowTreeHost() override;
+ void PrepareForShutdown() override;
+ void RegisterMirroringHost(AshWindowTreeHost* mirroring_ash_host) override;
+
+ // aura::WindowTreeHost:
+ ui::EventSource* GetEventSource() override;
+ gfx::AcceleratedWidget GetAcceleratedWidget() override;
+ void Show() override;
+ void Hide() override;
+ gfx::Rect GetBounds() const override;
+ void SetBounds(const gfx::Rect& bounds) override;
+ void SetCapture() override;
+ void ReleaseCapture() override;
+ gfx::Point GetLocationOnNativeScreen() const override;
+ void SetCursorNative(gfx::NativeCursor cursor) override;
+ void MoveCursorToNative(const gfx::Point& location) override;
+ void OnCursorVisibilityChangedNative(bool show) override;
+
+ // aura::WindowObserver:
+ void OnWindowDestroying(aura::Window* window) override;
+
+ // ui::EventSource:
+ ui::EventProcessor* GetEventProcessor() override;
+
+ std::vector<AshWindowTreeHost*> mirroring_hosts_;
+
+ gfx::Rect bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(AshWindowTreeHostUnified);
+};
+
+} // namespace ash
+
+#endif // ASH_HOST_ASH_WINDOW_TREE_HOST_UNIFIED_H_
diff --git a/ash/host/ash_window_tree_host_x11.cc b/ash/host/ash_window_tree_host_x11.cc
index 882ef13..c82d915 100644
--- a/ash/host/ash_window_tree_host_x11.cc
+++ b/ash/host/ash_window_tree_host_x11.cc
@@ -13,6 +13,7 @@
#include <vector>
#include "ash/host/ash_window_tree_host_init_params.h"
+#include "ash/host/ash_window_tree_host_unified.h"
#include "ash/host/root_window_transformer.h"
#include "base/basictypes.h"
#include "base/sys_info.h"
@@ -280,6 +281,8 @@ void AshWindowTreeHostX11::SetCrOSTapPaused(bool state) {
AshWindowTreeHost* AshWindowTreeHost::Create(
const AshWindowTreeHostInitParams& init_params) {
+ if (init_params.offscreen)
+ return new AshWindowTreeHostUnified(init_params.initial_bounds);
return new AshWindowTreeHostX11(init_params.initial_bounds);
}
diff --git a/ash/shell.cc b/ash/shell.cc
index 6bf50fe..024c87d 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -485,9 +485,11 @@ void Shell::RemoveShellObserver(ShellObserver* observer) {
#if defined(OS_CHROMEOS)
bool Shell::ShouldSaveDisplaySettings() {
+ // TODO(oshima): Allow saving the settings even in unified desktop mode.
return !(screen_orientation_controller_
->ignore_display_configuration_updates() ||
- resolution_notification_controller_->DoesNotificationTimeout());
+ resolution_notification_controller_->DoesNotificationTimeout()) &&
+ !switches::UnifiedDesktopEnabled();
}
#endif
diff --git a/ash/system/web_notification/web_notification_tray_unittest.cc b/ash/system/web_notification/web_notification_tray_unittest.cc
index 20e6893..6cf8cb1 100644
--- a/ash/system/web_notification/web_notification_tray_unittest.cc
+++ b/ash/system/web_notification/web_notification_tray_unittest.cc
@@ -290,12 +290,12 @@ TEST_F(WebNotificationTrayTest, MAYBE_PopupShownOnBothDisplays) {
// http://crbug.com/263664
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
- display_manager->SetSecondDisplayMode(DisplayManager::MIRRORING);
+ display_manager->SetMultiDisplayMode(DisplayManager::MIRRORING);
UpdateDisplay("400x400,200x200");
EXPECT_TRUE(GetTray()->IsPopupVisible());
EXPECT_FALSE(GetSecondaryTray());
- display_manager->SetSecondDisplayMode(DisplayManager::EXTENDED);
+ display_manager->SetMultiDisplayMode(DisplayManager::EXTENDED);
UpdateDisplay("400x400,200x200");
EXPECT_TRUE(GetTray()->IsPopupVisible());
secondary_tray = GetSecondaryTray();
diff --git a/ash/touch/touch_transformer_controller.cc b/ash/touch/touch_transformer_controller.cc
index d2582c0..269450e 100644
--- a/ash/touch/touch_transformer_controller.cc
+++ b/ash/touch/touch_transformer_controller.cc
@@ -142,7 +142,8 @@ void TouchTransformerController::UpdateTouchTransformer() const {
DisplayManager* display_manager = GetDisplayManager();
if (display_manager->num_connected_displays() == 0) {
return;
- } else if (display_manager->num_connected_displays() == 1) {
+ } else if (display_manager->num_connected_displays() == 1 ||
+ display_manager->multi_display_mode() == DisplayManager::UNIFIED) {
single_display_id = display_manager->first_display_id();
DCHECK(single_display_id != gfx::Display::kInvalidDisplayID);
single_display = display_manager->GetDisplayInfo(single_display_id);