diff options
author | oshima <oshima@chromium.org> | 2015-04-27 16:27:03 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-27 23:27:21 +0000 |
commit | 55ef921cb46ae2b1a95ddda8a376120db53eee69 (patch) | |
tree | d3b7ca8e0b457fe20567851b820ba5a6cdb5f77c /ash | |
parent | 172214038410fb835cc36721fcc2dc7b7a7dd5fd (diff) | |
download | chromium_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')
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); |