diff options
author | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-05 23:28:27 +0000 |
---|---|---|
committer | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-05 23:28:27 +0000 |
commit | c0ce80e3a85d17848197643ed4aaaae6136b91be (patch) | |
tree | dfa25e37db9a3b2b02b3a2f12cd9a1eaac4b687a | |
parent | 392c70f2320491e393556608cd140d367fce0fbd (diff) | |
download | chromium_src-c0ce80e3a85d17848197643ed4aaaae6136b91be.zip chromium_src-c0ce80e3a85d17848197643ed4aaaae6136b91be.tar.gz chromium_src-c0ce80e3a85d17848197643ed4aaaae6136b91be.tar.bz2 |
Show modal screen on all dislpays.
Rename ModalScreen to ModalBackground
remove unnecessary internal:: namespace.
I also fix the case when a window is created with a parent,
but not bounds is specified. It was incorrectly re-parented
to the display that contains (0,0).
BUG=151054
TEST=manual (see bug). added test case.
Review URL: https://chromiumcodereview.appspot.com/11031044
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@160513 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ash/display/screen_position_controller.cc | 4 | ||||
-rw-r--r-- | ash/root_window_controller.cc | 73 | ||||
-rw-r--r-- | ash/root_window_controller.h | 20 | ||||
-rw-r--r-- | ash/shell.cc | 45 | ||||
-rw-r--r-- | ash/shell.h | 18 | ||||
-rw-r--r-- | ash/wm/system_modal_container_layout_manager.cc | 124 | ||||
-rw-r--r-- | ash/wm/system_modal_container_layout_manager.h | 39 | ||||
-rw-r--r-- | ash/wm/system_modal_container_layout_manager_unittest.cc | 68 | ||||
-rw-r--r-- | ui/views/widget/native_widget_aura.cc | 16 |
9 files changed, 282 insertions, 125 deletions
diff --git a/ash/display/screen_position_controller.cc b/ash/display/screen_position_controller.cc index e8567ae..3f2c392 100644 --- a/ash/display/screen_position_controller.cc +++ b/ash/display/screen_position_controller.cc @@ -114,8 +114,8 @@ void ScreenPositionController::SetBounds(aura::Window* window, int container_id = window->parent()->id(); // All containers that uses screen coordinates must have valid window ids. DCHECK_GE(container_id, 0); - // Don't move modal screen. - if (!SystemModalContainerLayoutManager::IsModalScreen(window)) + // Don't move modal background. + if (!SystemModalContainerLayoutManager::IsModalBackground(window)) dst_container = Shell::GetContainer(dst_root, container_id); } diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc index 3b6e672..1f08095 100644 --- a/ash/root_window_controller.cc +++ b/ash/root_window_controller.cc @@ -122,7 +122,8 @@ void ReparentAllWindows(aura::RootWindow* src, aura::RootWindow* dst) { iter != children.end(); ++iter) { aura::Window* window = *iter; // Don't move modal screen. - if (internal::SystemModalContainerLayoutManager::IsModalScreen(window)) + if (internal::SystemModalContainerLayoutManager::IsModalBackground( + window)) continue; ReparentWindow(window, dst_container); @@ -144,8 +145,8 @@ RootWindowController::RootWindowController(aura::RootWindow* root_window) : root_window_(root_window) { SetRootWindowController(root_window, this); - event_client_.reset(new internal::EventClientImpl(root_window)); - screen_dimmer_.reset(new internal::ScreenDimmer(root_window)); + event_client_.reset(new EventClientImpl(root_window)); + screen_dimmer_.reset(new ScreenDimmer(root_window)); } RootWindowController::~RootWindowController() { @@ -171,25 +172,31 @@ void RootWindowController::Shutdown() { root_window_->PrepareForShutdown(); } +SystemModalContainerLayoutManager* +RootWindowController::GetSystemModalLayoutManager() { + return static_cast<SystemModalContainerLayoutManager*>( + GetContainer(kShellWindowId_SystemModalContainer)->layout_manager()); +} + aura::Window* RootWindowController::GetContainer(int container_id) { return root_window_->GetChildById(container_id); } void RootWindowController::InitLayoutManagers() { root_window_layout_ = - new internal::RootWindowLayoutManager(root_window_.get()); + new RootWindowLayoutManager(root_window_.get()); root_window_->SetLayoutManager(root_window_layout_); aura::Window* default_container = - GetContainer(internal::kShellWindowId_DefaultContainer); + GetContainer(kShellWindowId_DefaultContainer); // Workspace manager has its own layout managers. workspace_controller_.reset( - new internal::WorkspaceController(default_container)); + new WorkspaceController(default_container)); aura::Window* always_on_top_container = - GetContainer(internal::kShellWindowId_AlwaysOnTopContainer); + GetContainer(kShellWindowId_AlwaysOnTopContainer); always_on_top_container->SetLayoutManager( - new internal::BaseLayoutManager( + new BaseLayoutManager( always_on_top_container->GetRootWindow())); } @@ -278,44 +285,44 @@ void RootWindowController::CreateContainersInRootWindow( // container (moved back on unlock). We want to make sure that there's an // opaque layer occluding the non-lock-screen layers. - CreateContainer(internal::kShellWindowId_SystemBackgroundContainer, + CreateContainer(kShellWindowId_SystemBackgroundContainer, "SystemBackgroundContainer", root_window); aura::Window* desktop_background_containers = CreateContainer( - internal::kShellWindowId_DesktopBackgroundContainer, + kShellWindowId_DesktopBackgroundContainer, "DesktopBackgroundContainer", root_window); SetChildWindowVisibilityChangesAnimated(desktop_background_containers); aura::Window* non_lock_screen_containers = CreateContainer( - internal::kShellWindowId_NonLockScreenContainersContainer, + kShellWindowId_NonLockScreenContainersContainer, "NonLockScreenContainersContainer", root_window); aura::Window* lock_background_containers = CreateContainer( - internal::kShellWindowId_LockScreenBackgroundContainer, + kShellWindowId_LockScreenBackgroundContainer, "LockScreenBackgroundContainer", root_window); SetChildWindowVisibilityChangesAnimated(lock_background_containers); aura::Window* lock_screen_containers = CreateContainer( - internal::kShellWindowId_LockScreenContainersContainer, + kShellWindowId_LockScreenContainersContainer, "LockScreenContainersContainer", root_window); aura::Window* lock_screen_related_containers = CreateContainer( - internal::kShellWindowId_LockScreenRelatedContainersContainer, + kShellWindowId_LockScreenRelatedContainersContainer, "LockScreenRelatedContainersContainer", root_window); - CreateContainer(internal::kShellWindowId_UnparentedControlContainer, + CreateContainer(kShellWindowId_UnparentedControlContainer, "UnparentedControlContainer", non_lock_screen_containers); aura::Window* default_container = CreateContainer( - internal::kShellWindowId_DefaultContainer, + kShellWindowId_DefaultContainer, "DefaultContainer", non_lock_screen_containers); - if (!internal::WorkspaceController::IsWorkspace2Enabled()) { + if (!WorkspaceController::IsWorkspace2Enabled()) { default_container_handler_.reset( new ToplevelWindowEventHandler(default_container)); } @@ -323,7 +330,7 @@ void RootWindowController::CreateContainersInRootWindow( SetUsesScreenCoordinates(default_container); aura::Window* always_on_top_container = CreateContainer( - internal::kShellWindowId_AlwaysOnTopContainer, + kShellWindowId_AlwaysOnTopContainer, "AlwaysOnTopContainer", non_lock_screen_containers); always_on_top_container_handler_.reset( @@ -332,36 +339,36 @@ void RootWindowController::CreateContainersInRootWindow( SetUsesScreenCoordinates(always_on_top_container); aura::Window* panel_container = CreateContainer( - internal::kShellWindowId_PanelContainer, + kShellWindowId_PanelContainer, "PanelContainer", non_lock_screen_containers); SetUsesScreenCoordinates(panel_container); aura::Window* launcher_container = - CreateContainer(internal::kShellWindowId_LauncherContainer, + CreateContainer(kShellWindowId_LauncherContainer, "LauncherContainer", non_lock_screen_containers); SetUsesScreenCoordinates(launcher_container); aura::Window* app_list_container = - CreateContainer(internal::kShellWindowId_AppListContainer, + CreateContainer(kShellWindowId_AppListContainer, "AppListContainer", non_lock_screen_containers); SetUsesScreenCoordinates(app_list_container); aura::Window* modal_container = CreateContainer( - internal::kShellWindowId_SystemModalContainer, + kShellWindowId_SystemModalContainer, "SystemModalContainer", non_lock_screen_containers); modal_container_handler_.reset( new ToplevelWindowEventHandler(modal_container)); modal_container->SetLayoutManager( - new internal::SystemModalContainerLayoutManager(modal_container)); + new SystemModalContainerLayoutManager(modal_container)); SetChildWindowVisibilityChangesAnimated(modal_container); SetUsesScreenCoordinates(modal_container); aura::Window* input_method_container = CreateContainer( - internal::kShellWindowId_InputMethodContainer, + kShellWindowId_InputMethodContainer, "InputMethodContainer", non_lock_screen_containers); SetUsesScreenCoordinates(input_method_container); @@ -369,54 +376,54 @@ void RootWindowController::CreateContainersInRootWindow( // TODO(beng): Figure out if we can make this use // SystemModalContainerEventFilter instead of stops_event_propagation. aura::Window* lock_container = CreateContainer( - internal::kShellWindowId_LockScreenContainer, + kShellWindowId_LockScreenContainer, "LockScreenContainer", lock_screen_containers); lock_container->SetLayoutManager( - new internal::BaseLayoutManager(root_window)); + new BaseLayoutManager(root_window)); SetUsesScreenCoordinates(lock_container); // TODO(beng): stopsevents aura::Window* lock_modal_container = CreateContainer( - internal::kShellWindowId_LockSystemModalContainer, + kShellWindowId_LockSystemModalContainer, "LockSystemModalContainer", lock_screen_containers); lock_modal_container_handler_.reset( new ToplevelWindowEventHandler(lock_modal_container)); lock_modal_container->SetLayoutManager( - new internal::SystemModalContainerLayoutManager(lock_modal_container)); + new SystemModalContainerLayoutManager(lock_modal_container)); SetChildWindowVisibilityChangesAnimated(lock_modal_container); SetUsesScreenCoordinates(lock_modal_container); aura::Window* status_container = - CreateContainer(internal::kShellWindowId_StatusContainer, + CreateContainer(kShellWindowId_StatusContainer, "StatusContainer", lock_screen_related_containers); SetUsesScreenCoordinates(status_container); aura::Window* settings_bubble_container = CreateContainer( - internal::kShellWindowId_SettingBubbleContainer, + kShellWindowId_SettingBubbleContainer, "SettingBubbleContainer", lock_screen_related_containers); SetChildWindowVisibilityChangesAnimated(settings_bubble_container); SetUsesScreenCoordinates(settings_bubble_container); aura::Window* menu_container = CreateContainer( - internal::kShellWindowId_MenuContainer, + kShellWindowId_MenuContainer, "MenuContainer", lock_screen_related_containers); SetChildWindowVisibilityChangesAnimated(menu_container); SetUsesScreenCoordinates(menu_container); aura::Window* drag_drop_container = CreateContainer( - internal::kShellWindowId_DragImageAndTooltipContainer, + kShellWindowId_DragImageAndTooltipContainer, "DragImageAndTooltipContainer", lock_screen_related_containers); SetChildWindowVisibilityChangesAnimated(drag_drop_container); SetUsesScreenCoordinates(drag_drop_container); aura::Window* overlay_container = CreateContainer( - internal::kShellWindowId_OverlayContainer, + kShellWindowId_OverlayContainer, "OverlayContainer", lock_screen_related_containers); SetUsesScreenCoordinates(overlay_container); diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h index 29f9c04..e8f623d 100644 --- a/ash/root_window_controller.h +++ b/ash/root_window_controller.h @@ -5,6 +5,7 @@ #ifndef ASH_ROOT_WINDOW_CONTROLLER_H_ #define ASH_ROOT_WINDOW_CONTROLLER_H_ +#include "ash/ash_export.h" #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" @@ -28,6 +29,7 @@ class EventClientImpl; class RootWindowLayoutManager; class ScreenDimmer; class SystemBackgroundController; +class SystemModalContainerLayoutManager; class WorkspaceController; // This class maintains the per root window state for ash. This class @@ -35,7 +37,7 @@ class WorkspaceController; // deleted upon the deletion of the root window. The RootWindowController // for particular root window is stored as a property and can be obtained // using |GetRootWindowController(aura::RootWindow*)| function. -class RootWindowController { +class ASH_EXPORT RootWindowController { public: explicit RootWindowController(aura::RootWindow* root_window); ~RootWindowController(); @@ -44,18 +46,20 @@ class RootWindowController { return root_window_.get(); } - internal::RootWindowLayoutManager* root_window_layout() { + RootWindowLayoutManager* root_window_layout() { return root_window_layout_; } - internal::WorkspaceController* workspace_controller() { + WorkspaceController* workspace_controller() { return workspace_controller_.get(); } - internal::ScreenDimmer* screen_dimmer() { + ScreenDimmer* screen_dimmer() { return screen_dimmer_.get(); } + SystemModalContainerLayoutManager* GetSystemModalLayoutManager(); + aura::Window* GetContainer(int container_id); void InitLayoutManagers(); @@ -89,7 +93,7 @@ class RootWindowController { void CreateContainersInRootWindow(aura::RootWindow* root_window); scoped_ptr<aura::RootWindow> root_window_; - internal::RootWindowLayoutManager* root_window_layout_; + RootWindowLayoutManager* root_window_layout_; // A background layer that's displayed beneath all other layers. Without // this, portions of the root window that aren't covered by layers will be @@ -98,9 +102,9 @@ class RootWindowController { scoped_ptr<SystemBackgroundController> background_; // An event filter that pre-handles all key events to send them to an IME. - scoped_ptr<internal::EventClientImpl> event_client_; - scoped_ptr<internal::ScreenDimmer> screen_dimmer_; - scoped_ptr<internal::WorkspaceController> workspace_controller_; + scoped_ptr<EventClientImpl> event_client_; + scoped_ptr<ScreenDimmer> screen_dimmer_; + scoped_ptr<WorkspaceController> workspace_controller_; // We need to own event handlers for various containers. scoped_ptr<ToplevelWindowEventHandler> default_container_handler_; diff --git a/ash/shell.cc b/ash/shell.cc index 560e5e8..3627616 100644 --- a/ash/shell.cc +++ b/ash/shell.cc @@ -55,6 +55,7 @@ #include "ash/wm/stacking_controller.h" #include "ash/wm/status_area_layout_manager.h" #include "ash/wm/system_gesture_event_filter.h" +#include "ash/wm/system_modal_container_event_filter.h" #include "ash/wm/system_modal_container_layout_manager.h" #include "ash/wm/user_activity_detector.h" #include "ash/wm/video_detector.h" @@ -656,6 +657,34 @@ void Shell::SetDimming(bool should_dim) { (*iter)->screen_dimmer()->SetDimming(should_dim); } +void Shell::CreateModalBackground() { + if (!modality_filter_.get()) { + modality_filter_.reset(new internal::SystemModalContainerEventFilter(this)); + AddEnvEventFilter(modality_filter_.get()); + } + RootWindowControllerList controllers = GetAllRootWindowControllers(); + for (RootWindowControllerList::iterator iter = controllers.begin(); + iter != controllers.end(); ++iter) + (*iter)->GetSystemModalLayoutManager()->CreateModalBackground(); +} + +void Shell::OnModalWindowRemoved(aura::Window* removed) { + RootWindowControllerList controllers = GetAllRootWindowControllers(); + bool activated = false; + for (RootWindowControllerList::iterator iter = controllers.begin(); + iter != controllers.end() && !activated; ++iter) { + activated = + (*iter)->GetSystemModalLayoutManager()->ActivateNextModalWindow(); + } + if (!activated) { + RemoveEnvEventFilter(modality_filter_.get()); + modality_filter_.reset(); + for (RootWindowControllerList::iterator iter = controllers.begin(); + iter != controllers.end(); ++iter) + (*iter)->GetSystemModalLayoutManager()->DestroyModalBackground(); + } +} + SystemTrayDelegate* Shell::tray_delegate() { return status_area_widget_->system_tray_delegate(); } @@ -722,6 +751,10 @@ void Shell::InitRootWindowController( root_window->GetChildById(internal::kShellWindowId_AlwaysOnTopContainer)); root_window->SetProperty(internal::kAlwaysOnTopControllerKey, always_on_top_controller); + if (GetPrimaryRootWindowController()->GetSystemModalLayoutManager()-> + has_modal_background()) { + controller->GetSystemModalLayoutManager()->CreateModalBackground(); + } window_cycle_controller_->OnRootWindowAdded(root_window); } @@ -776,4 +809,16 @@ void Shell::ShowCursor(bool visible) { (*iter)->ShowCursor(visible); } +bool Shell::CanWindowReceiveEvents(aura::Window* window) { + RootWindowControllerList controllers = GetAllRootWindowControllers(); + for (RootWindowControllerList::iterator iter = controllers.begin(); + iter != controllers.end(); ++iter) { + if ((*iter)->GetSystemModalLayoutManager()-> + CanWindowReceiveEvents(window)) { + return true; + } + } + return false; +} + } // namespace ash diff --git a/ash/shell.h b/ash/shell.h index a1cebe6..ef869bf 100644 --- a/ash/shell.h +++ b/ash/shell.h @@ -13,6 +13,7 @@ #include "ash/wm/cursor_delegate.h" #include "ash/wm/cursor_manager.h" #include "ash/wm/shelf_types.h" +#include "ash/wm/system_modal_container_event_filter_delegate.h" #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" @@ -100,6 +101,7 @@ class SlowAnimationEventFilter; class StackingController; class StatusAreaWidget; class SystemGestureEventFilter; +class SystemModalContainerEventFilter; class TooltipController; class TouchObserverHUD; class VisibilityController; @@ -112,7 +114,8 @@ class WorkspaceController; // // Upon creation, the Shell sets itself as the RootWindow's delegate, which // takes ownership of the Shell. -class ASH_EXPORT Shell : ash::CursorDelegate { +class ASH_EXPORT Shell : CursorDelegate, + internal::SystemModalContainerEventFilterDelegate { public: typedef std::vector<aura::RootWindow*> RootWindowList; typedef std::vector<internal::RootWindowController*> RootWindowControllerList; @@ -318,6 +321,15 @@ class ASH_EXPORT Shell : ash::CursorDelegate { // Dims or undims the screen. void SetDimming(bool should_dim); + // Creates modal background, which is a partially-opaque fullscreen + // window, on all displays. + void CreateModalBackground(); + + // Called when a modal window is removed. It will activate + // another modal window if any, or remove modal screens + // on all displays. + void OnModalWindowRemoved(aura::Window* removed); + // TODO(sky): don't expose this! internal::ShelfLayoutManager* shelf() const { return shelf_; } @@ -388,6 +400,9 @@ class ASH_EXPORT Shell : ash::CursorDelegate { virtual void SetCursor(gfx::NativeCursor cursor) OVERRIDE; virtual void ShowCursor(bool visible) OVERRIDE; + // ash::internal::SystemModalContainerEventFilterDelegate overrides: + virtual bool CanWindowReceiveEvents(aura::Window* window) OVERRIDE; + static Shell* instance_; // If set before the Shell is initialized, the mouse cursor will be hidden @@ -441,6 +456,7 @@ class ASH_EXPORT Shell : ash::CursorDelegate { scoped_ptr<aura::client::UserActionClient> user_action_client_; scoped_ptr<internal::MouseCursorEventFilter> mouse_cursor_filter_; scoped_ptr<internal::ScreenPositionController> screen_position_controller_; + scoped_ptr<internal::SystemModalContainerEventFilter> modality_filter_; // An event filter that rewrites or drops an event. scoped_ptr<internal::EventRewriterEventFilter> event_rewriter_filter_; diff --git a/ash/wm/system_modal_container_layout_manager.cc b/ash/wm/system_modal_container_layout_manager.cc index 3985c72..c763bc9 100644 --- a/ash/wm/system_modal_container_layout_manager.cc +++ b/ash/wm/system_modal_container_layout_manager.cc @@ -22,6 +22,7 @@ #include "ui/compositor/layer_animator.h" #include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/gfx/canvas.h" +#include "ui/gfx/screen.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" @@ -30,10 +31,10 @@ namespace internal { namespace { -class ScreenView : public views::View { +class ModalBackgroundView : public views::View { public: - ScreenView() {} - virtual ~ScreenView() {} + ModalBackgroundView() {} + virtual ~ModalBackgroundView() {} // Overridden from views::View: virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { @@ -49,7 +50,7 @@ class ScreenView : public views::View { return SK_ColorBLACK; } - DISALLOW_COPY_AND_ASSIGN(ScreenView); + DISALLOW_COPY_AND_ASSIGN(ModalBackgroundView); }; } // namespace @@ -60,9 +61,7 @@ class ScreenView : public views::View { SystemModalContainerLayoutManager::SystemModalContainerLayoutManager( aura::Window* container) : container_(container), - modal_screen_(NULL), - ALLOW_THIS_IN_INITIALIZER_LIST(modality_filter_( - new SystemModalContainerEventFilter(this))) { + modal_background_(NULL) { } SystemModalContainerLayoutManager::~SystemModalContainerLayoutManager() { @@ -72,9 +71,10 @@ SystemModalContainerLayoutManager::~SystemModalContainerLayoutManager() { // SystemModalContainerLayoutManager, aura::LayoutManager implementation: void SystemModalContainerLayoutManager::OnWindowResized() { - if (modal_screen_) { + if (modal_background_) { // Note: we have to set the entire bounds with the screen offset. - modal_screen_->SetBounds(container_->bounds()); + modal_background_->SetBounds( + gfx::Screen::GetDisplayNearestWindow(container_).bounds()); } if (!modal_windows_.empty()) { aura::Window::Windows::iterator it = modal_windows_.begin(); @@ -86,7 +86,7 @@ void SystemModalContainerLayoutManager::OnWindowResized() { void SystemModalContainerLayoutManager::OnWindowAddedToLayout( aura::Window* child) { - DCHECK((modal_screen_ && child == modal_screen_->GetNativeView()) || + DCHECK((modal_background_ && child == modal_background_->GetNativeView()) || child->type() == aura::client::WINDOW_TYPE_NORMAL || child->type() == aura::client::WINDOW_TYPE_POPUP); child->AddObserver(this); @@ -135,8 +135,8 @@ void SystemModalContainerLayoutManager::OnWindowPropertyChanged( void SystemModalContainerLayoutManager::OnWindowDestroying( aura::Window* window) { - if (modal_screen_ && modal_screen_->GetNativeView() == window) - modal_screen_ = NULL; + if (modal_background_ && modal_background_->GetNativeView() == window) + modal_background_ = NULL; } @@ -154,12 +154,59 @@ bool SystemModalContainerLayoutManager::CanWindowReceiveEvents( return wm::GetActivatableWindow(window) == modal_window(); } -bool SystemModalContainerLayoutManager::IsModalScreen( +bool SystemModalContainerLayoutManager::ActivateNextModalWindow() { + if (modal_windows_.empty()) + return false; + wm::ActivateWindow(modal_window()); + return true; +} + +void SystemModalContainerLayoutManager::CreateModalBackground() { + if (!modal_background_) { + modal_background_ = new views::Widget; + views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL); + params.parent = container_; + params.bounds = gfx::Screen::GetDisplayNearestWindow(container_).bounds(); + modal_background_->Init(params); + modal_background_->GetNativeView()->SetName( + "SystemModalContainerLayoutManager.ModalBackground"); + modal_background_->SetContentsView(new ModalBackgroundView); + modal_background_->GetNativeView()->layer()->SetOpacity(0.0f); + } + + ui::ScopedLayerAnimationSettings settings( + modal_background_->GetNativeView()->layer()->GetAnimator()); + modal_background_->Show(); + modal_background_->GetNativeView()->layer()->SetOpacity(0.5f); + container_->StackChildAtTop(modal_background_->GetNativeView()); +} + +void SystemModalContainerLayoutManager::DestroyModalBackground() { + // modal_background_ can be NULL when a root window is shutting down + // and OnWindowDestroying is called first. + if (modal_background_) { + ui::ScopedLayerAnimationSettings settings( + modal_background_->GetNativeView()->layer()->GetAnimator()); + modal_background_->Close(); + settings.AddObserver(CreateHidingWindowAnimationObserver( + modal_background_->GetNativeView())); + modal_background_->GetNativeView()->layer()->SetOpacity(0.0f); + modal_background_ = NULL; + } +} + +// static +bool SystemModalContainerLayoutManager::IsModalBackground( aura::Window* window) { int id = window->parent()->id(); - return (id == internal::kShellWindowId_SystemModalContainer || - id == internal::kShellWindowId_LockSystemModalContainer) && - window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_NONE; + if (id != internal::kShellWindowId_SystemModalContainer && + id != internal::kShellWindowId_LockSystemModalContainer) + return false; + SystemModalContainerLayoutManager* layout_manager = + static_cast<SystemModalContainerLayoutManager*>( + window->parent()->layout_manager()); + return layout_manager->modal_background_ && + layout_manager->modal_background_->GetNativeWindow() == window; } //////////////////////////////////////////////////////////////////////////////// @@ -172,7 +219,7 @@ void SystemModalContainerLayoutManager::AddModalWindow(aura::Window* window) { capture_window->ReleaseCapture(); } modal_windows_.push_back(window); - CreateModalScreen(); + Shell::GetInstance()->CreateModalBackground(); } void SystemModalContainerLayoutManager::RemoveModalWindow( @@ -182,48 +229,7 @@ void SystemModalContainerLayoutManager::RemoveModalWindow( if (it != modal_windows_.end()) modal_windows_.erase(it); - if (modal_windows_.empty()) - DestroyModalScreen(); - else - wm::ActivateWindow(modal_window()); -} - -void SystemModalContainerLayoutManager::CreateModalScreen() { - if (!modal_screen_) { - modal_screen_ = new views::Widget; - views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL); - params.parent = container_; - params.bounds = gfx::Rect(0, 0, container_->bounds().width(), - container_->bounds().height()); - modal_screen_->Init(params); - modal_screen_->GetNativeView()->SetName( - "SystemModalContainerLayoutManager.ModalScreen"); - modal_screen_->SetContentsView(new ScreenView); - modal_screen_->GetNativeView()->layer()->SetOpacity(0.0f); - - Shell::GetInstance()->env_filter()->AddFilter(modality_filter_.get()); - } - - ui::ScopedLayerAnimationSettings settings( - modal_screen_->GetNativeView()->layer()->GetAnimator()); - modal_screen_->Show(); - modal_screen_->GetNativeView()->layer()->SetOpacity(0.5f); - container_->StackChildAtTop(modal_screen_->GetNativeView()); -} - -void SystemModalContainerLayoutManager::DestroyModalScreen() { - Shell::GetInstance()->env_filter()->RemoveFilter(modality_filter_.get()); - // modal_screen_ can be NULL when a root window is shutting down - // and OnWindowDestroying is called first. - if (modal_screen_) { - ui::ScopedLayerAnimationSettings settings( - modal_screen_->GetNativeView()->layer()->GetAnimator()); - modal_screen_->Close(); - settings.AddObserver( - CreateHidingWindowAnimationObserver(modal_screen_->GetNativeView())); - modal_screen_->GetNativeView()->layer()->SetOpacity(0.0f); - modal_screen_ = NULL; - } + Shell::GetInstance()->OnModalWindowRemoved(window); } } // namespace internal diff --git a/ash/wm/system_modal_container_layout_manager.h b/ash/wm/system_modal_container_layout_manager.h index f2aa51c..76618ec 100644 --- a/ash/wm/system_modal_container_layout_manager.h +++ b/ash/wm/system_modal_container_layout_manager.h @@ -7,13 +7,12 @@ #include <vector> -#include "ash/wm/system_modal_container_event_filter_delegate.h" +#include "ash/ash_export.h" #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" #include "ui/aura/layout_manager.h" #include "ui/aura/window_observer.h" -#include "ash/ash_export.h" namespace aura { class Window; @@ -32,12 +31,13 @@ namespace internal { // LayoutManager for the modal window container. class ASH_EXPORT SystemModalContainerLayoutManager : public aura::LayoutManager, - public aura::WindowObserver, - public SystemModalContainerEventFilterDelegate { + public aura::WindowObserver { public: explicit SystemModalContainerLayoutManager(aura::Window* container); virtual ~SystemModalContainerLayoutManager(); + bool has_modal_background() const { return modal_background_ != NULL; } + // Overridden from aura::LayoutManager: virtual void OnWindowResized() OVERRIDE; virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE; @@ -54,19 +54,27 @@ class ASH_EXPORT SystemModalContainerLayoutManager intptr_t old) OVERRIDE; virtual void OnWindowDestroying(aura::Window* window) OVERRIDE; - // Overridden from SystemModalContainerEventFilterDelegate: - virtual bool CanWindowReceiveEvents(aura::Window* window) OVERRIDE; + // Can a given |window| receive and handle input events? + bool CanWindowReceiveEvents(aura::Window* window); + + // Activates next modal window if any. Returns false if there + // are no more modal windows in this layout manager. + bool ActivateNextModalWindow(); - // Is the |window| modal screen? - static bool IsModalScreen(aura::Window* window); + // Creates modal background window, which is a partially-opaque + // fullscreen window. If there is already a modal background window, + // it will bring it the top. + void CreateModalBackground(); + + void DestroyModalBackground(); + + // Is the |window| modal background? + static bool IsModalBackground(aura::Window* window); private: void AddModalWindow(aura::Window* window); void RemoveModalWindow(aura::Window* window); - void CreateModalScreen(); - void DestroyModalScreen(); - aura::Window* modal_window() { return !modal_windows_.empty() ? modal_windows_.back() : NULL; } @@ -74,18 +82,13 @@ class ASH_EXPORT SystemModalContainerLayoutManager // The container that owns the layout manager. aura::Window* container_; - // A "screen" widget that dims the windows behind the modal window(s) being + // A widget that dims the windows behind the modal window(s) being // shown in |container_|. - views::Widget* modal_screen_; + views::Widget* modal_background_; // A stack of modal windows. Only the topmost can receive events. std::vector<aura::Window*> modal_windows_; - // An event filter that enforces the modality of the topmost window in - // |modal_windows_|. The event filter is attached when a modal window is - // added, and removed when the last is closed. - scoped_ptr<aura::EventFilter> modality_filter_; - DISALLOW_COPY_AND_ASSIGN(SystemModalContainerLayoutManager); }; diff --git a/ash/wm/system_modal_container_layout_manager_unittest.cc b/ash/wm/system_modal_container_layout_manager_unittest.cc index 33397e6..90a6a19 100644 --- a/ash/wm/system_modal_container_layout_manager_unittest.cc +++ b/ash/wm/system_modal_container_layout_manager_unittest.cc @@ -4,6 +4,7 @@ #include "ash/wm/system_modal_container_layout_manager.h" +#include "ash/root_window_controller.h" #include "ash/shell.h" #include "ash/shell_delegate.h" #include "ash/shell_window_ids.h" @@ -15,6 +16,7 @@ #include "ui/aura/test/event_generator.h" #include "ui/aura/window.h" #include "ui/compositor/layer.h" +#include "ui/gfx/screen.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" @@ -29,6 +31,19 @@ aura::Window* GetModalContainer() { ash::internal::kShellWindowId_SystemModalContainer); } +bool AllRootWindowsHaveModalBackgrounds() { + Shell::RootWindowControllerList controllers = + Shell::GetAllRootWindowControllers(); + bool has_modal_screen = !controllers.empty(); + for (Shell::RootWindowControllerList::const_iterator iter = + controllers.begin(); + iter != controllers.end(); ++iter) { + has_modal_screen &= + (*iter)->GetSystemModalLayoutManager()->has_modal_background(); + } + return has_modal_screen; +} + class TestWindow : public views::WidgetDelegateView { public: explicit TestWindow(bool modal) : modal_(modal) {} @@ -341,5 +356,58 @@ TEST_F(SystemModalContainerLayoutManagerTest, KeepVisible) { EXPECT_EQ(bounds, gfx::Rect(700, 500, 100, 100)); } +TEST_F(SystemModalContainerLayoutManagerTest, MultiDisplays) { + UpdateDisplay("500x500,500x500"); + + scoped_ptr<aura::Window> normal(TestWindow::OpenTestWindow(NULL, false)); + normal->SetBounds(gfx::Rect(100, 100, 50, 50)); + + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + EXPECT_EQ(2U, root_windows.size()); + aura::Window* container1 = Shell::GetContainer( + root_windows[0], ash::internal::kShellWindowId_SystemModalContainer); + aura::Window* container2 = Shell::GetContainer( + root_windows[1], ash::internal::kShellWindowId_SystemModalContainer); + + scoped_ptr<aura::Window> modal1( + TestWindow::OpenTestWindow(container1, true)); + EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds()); + EXPECT_TRUE(wm::IsActiveWindow(modal1.get())); + + scoped_ptr<aura::Window> modal11( + TestWindow::OpenTestWindow(container1, true)); + EXPECT_TRUE(wm::IsActiveWindow(modal11.get())); + + scoped_ptr<aura::Window> modal2( + TestWindow::OpenTestWindow(container2, true)); + EXPECT_TRUE(wm::IsActiveWindow(modal2.get())); + + // Sanity check if they're on the correct containers. + EXPECT_EQ(container1, modal1->parent()); + EXPECT_EQ(container1, modal11->parent()); + EXPECT_EQ(container2, modal2->parent()); + + modal2.reset(); + EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds()); + EXPECT_TRUE(wm::IsActiveWindow(modal11.get())); + + modal11.reset(); + EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds()); + EXPECT_TRUE(wm::IsActiveWindow(modal1.get())); + + UpdateDisplay("500x500"); + EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds()); + EXPECT_TRUE(wm::IsActiveWindow(modal1.get())); + + UpdateDisplay("500x500,600x600"); + EXPECT_TRUE(AllRootWindowsHaveModalBackgrounds()); + EXPECT_TRUE(wm::IsActiveWindow(modal1.get())); + + // No more modal screen. + modal1.reset(); + EXPECT_FALSE(AllRootWindowsHaveModalBackgrounds()); + EXPECT_TRUE(wm::IsActiveWindow(normal.get())); +} + } // namespace test } // namespace ash diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc index ecd71bc..ee2fe37 100644 --- a/ui/views/widget/native_widget_aura.cc +++ b/ui/views/widget/native_widget_aura.cc @@ -176,6 +176,8 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) { window_->Show(); delegate_->OnNativeWidgetCreated(); + + gfx::Rect window_bounds = params.bounds; if (desktop_helper_.get() && desktop_helper_->GetRootWindow()) { if (!params.child && params.GetParent()) params.GetParent()->AddTransientChild(window_); @@ -203,10 +205,16 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) { // SetAlwaysOnTop before SetParent so that always-on-top container is used. SetAlwaysOnTop(params.keep_on_top); // If the parent is not specified, find the default parent for - // the |window_| using the desired |params.bounds|. + // the |window_| using the desired |window_bounds|. if (!parent) { parent = aura::client::GetStackingClient()->GetDefaultParent( - window_, params.bounds); + window_, window_bounds); + } else if (window_bounds == gfx::Rect()) { + // If a parent is specified but no bounds are given, + // use the origin of the parent's display so that the widget + // will be added to the same display as the parent. + gfx::Rect bounds = gfx::Screen::GetDisplayNearestWindow(parent).bounds(); + window_bounds.set_origin(bounds.origin()); } window_->SetParent(parent); } @@ -215,9 +223,9 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) { // true state/bounds (the LayoutManager may enforce a particular // state/bounds). if (IsMaximized()) - SetRestoreBounds(window_, params.bounds); + SetRestoreBounds(window_, window_bounds); else - SetBounds(params.bounds); + SetBounds(window_bounds); window_->set_ignore_events(!params.accept_events); can_activate_ = params.can_activate && params.type != Widget::InitParams::TYPE_CONTROL; |