diff options
-rw-r--r-- | ash/shell.cc | 3 | ||||
-rw-r--r-- | ash/shell.h | 7 | ||||
-rw-r--r-- | ash/wm/ash_focus_rules.cc | 37 | ||||
-rw-r--r-- | ash/wm/ash_focus_rules.h | 3 | ||||
-rw-r--r-- | ash/wm/panel_layout_manager_unittest.cc | 6 | ||||
-rw-r--r-- | ash/wm/toplevel_window_event_handler_unittest.cc | 35 | ||||
-rw-r--r-- | ash/wm/window_manager_unittest.cc | 11 | ||||
-rw-r--r-- | ui/views/bubble/bubble_delegate.cc | 1 | ||||
-rw-r--r-- | ui/views/corewm/base_focus_rules.cc | 25 | ||||
-rw-r--r-- | ui/views/corewm/focus_controller.cc | 32 | ||||
-rw-r--r-- | ui/views/corewm/focus_controller.h | 2 | ||||
-rw-r--r-- | ui/views/corewm/focus_controller_unittest.cc | 86 | ||||
-rw-r--r-- | ui/views/corewm/window_modality_controller.cc | 18 | ||||
-rw-r--r-- | ui/views/corewm/window_modality_controller.h | 3 |
14 files changed, 211 insertions, 58 deletions
diff --git a/ash/shell.cc b/ash/shell.cc index 1651251..0d4461c 100644 --- a/ash/shell.cc +++ b/ash/shell.cc @@ -898,7 +898,8 @@ void Shell::OnEvent(ui::Event* event) { void Shell::OnWindowActivated(aura::Window* gained_active, aura::Window* lost_active) { - active_root_window_ = gained_active->GetRootWindow(); + if (gained_active) + active_root_window_ = gained_active->GetRootWindow(); } } // namespace ash diff --git a/ash/shell.h b/ash/shell.h index e8156e0..34de721 100644 --- a/ash/shell.h +++ b/ash/shell.h @@ -336,6 +336,9 @@ class ASH_EXPORT Shell PartialMagnificationController* partial_magnification_controller() { return partial_magnification_controller_.get(); } + aura::client::ActivationClient* activation_client() { + return activation_client_; + } ScreenAsh* screen() { return screen_; } @@ -403,10 +406,6 @@ class ASH_EXPORT Shell browser_context_ = browser_context; } - aura::client::ActivationClient* activation_client() { - return activation_client_; - } - // Initializes the root window to be used for a secondary display. void InitRootWindowForSecondaryDisplay(aura::RootWindow* root); diff --git a/ash/wm/ash_focus_rules.cc b/ash/wm/ash_focus_rules.cc index bb46e63..39459f6 100644 --- a/ash/wm/ash_focus_rules.cc +++ b/ash/wm/ash_focus_rules.cc @@ -104,30 +104,30 @@ aura::Window* AshFocusRules::GetNextActivatableWindow( aura::Window* ignore) const { DCHECK(ignore); - size_t current_container_index = 0; + int starting_container_index = 0; // If the container of the window losing focus is in the list, start from that // container. aura::RootWindow* root = ignore->GetRootWindow(); if (!root) root = Shell::GetActiveRootWindow(); - for (size_t i = 0; ignore && i < arraysize(kWindowContainerIds); i++) { + int container_count = static_cast<int>(arraysize(kWindowContainerIds)); + for (int i = 0; ignore && i < container_count; i++) { aura::Window* container = Shell::GetContainer(root, kWindowContainerIds[i]); if (container && container->Contains(ignore)) { - current_container_index = i; + starting_container_index = i; break; } } - // Look for windows to focus in that container and below. + // Look for windows to focus in |ignore|'s container. If none are found, we + // look in all the containers in front of |ignore|'s container, then all + // behind. aura::Window* window = NULL; - for (; !window && current_container_index < arraysize(kWindowContainerIds); - current_container_index++) { - aura::Window::Windows containers = - Shell::GetAllContainers(kWindowContainerIds[current_container_index]); - for (aura::Window::Windows::const_iterator iter = containers.begin(); - iter != containers.end() && !window; ++iter) { - window = GetTopmostWindowToActivateInContainer((*iter), ignore); - } + for (int i = starting_container_index; !window && i < container_count; i++) + window = GetTopmostWindowToActivateForContainerIndex(i, ignore); + if (!window && starting_container_index > 0) { + for (int i = starting_container_index - 1; !window && i >= 0; i--) + window = GetTopmostWindowToActivateForContainerIndex(i, ignore); } return window; } @@ -135,6 +135,19 @@ aura::Window* AshFocusRules::GetNextActivatableWindow( //////////////////////////////////////////////////////////////////////////////// // AshFocusRules, private: +aura::Window* AshFocusRules::GetTopmostWindowToActivateForContainerIndex( + int index, + aura::Window* ignore) const { + aura::Window* window = NULL; + aura::Window::Windows containers = + Shell::GetAllContainers(kWindowContainerIds[index]); + for (aura::Window::Windows::const_iterator iter = containers.begin(); + iter != containers.end() && !window; ++iter) { + window = GetTopmostWindowToActivateInContainer((*iter), ignore); + } + return window; +} + aura::Window* AshFocusRules::GetTopmostWindowToActivateInContainer( aura::Window* container, aura::Window* ignore) const { diff --git a/ash/wm/ash_focus_rules.h b/ash/wm/ash_focus_rules.h index bb4cfca..f53a70b 100644 --- a/ash/wm/ash_focus_rules.h +++ b/ash/wm/ash_focus_rules.h @@ -27,6 +27,9 @@ class ASH_EXPORT AshFocusRules : public views::corewm::BaseFocusRules { virtual aura::Window* GetNextActivatableWindow( aura::Window* ignore) const OVERRIDE; + aura::Window* GetTopmostWindowToActivateForContainerIndex( + int index, + aura::Window* ignore) const; aura::Window* GetTopmostWindowToActivateInContainer( aura::Window* container, aura::Window* ignore) const; diff --git a/ash/wm/panel_layout_manager_unittest.cc b/ash/wm/panel_layout_manager_unittest.cc index bbbbc92..a3e5e3c 100644 --- a/ash/wm/panel_layout_manager_unittest.cc +++ b/ash/wm/panel_layout_manager_unittest.cc @@ -18,6 +18,7 @@ #include "ui/aura/client/aura_constants.h" #include "ui/aura/test/test_windows.h" #include "ui/aura/window.h" +#include "ui/views/corewm/corewm_switches.h" #include "ui/views/widget/widget.h" namespace ash { @@ -207,7 +208,10 @@ TEST_F(PanelLayoutManagerTest, MultiplePanelCallout) { wm::ActivateWindow(w3.get()); EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w3.get())); w3.reset(); - EXPECT_FALSE(IsCalloutVisible()); + if (views::corewm::UseFocusController()) + EXPECT_NO_FATAL_FAILURE(IsCalloutAboveLauncherIcon(w2.get())); + else + EXPECT_FALSE(IsCalloutVisible()); } // Tests removing panels. diff --git a/ash/wm/toplevel_window_event_handler_unittest.cc b/ash/wm/toplevel_window_event_handler_unittest.cc index f2457de..16703b3 100644 --- a/ash/wm/toplevel_window_event_handler_unittest.cc +++ b/ash/wm/toplevel_window_event_handler_unittest.cc @@ -5,6 +5,7 @@ #include "ash/wm/toplevel_window_event_handler.h" #include "ash/shell.h" +#include "ash/shell_window_ids.h" #include "ash/test/ash_test_base.h" #include "ash/wm/property_util.h" #include "ash/wm/window_util.h" @@ -68,34 +69,19 @@ class TestWindowDelegate : public aura::test::TestWindowDelegate { class ToplevelWindowEventHandlerTest : public AshTestBase { public: - ToplevelWindowEventHandlerTest() : parent_(NULL) {} + ToplevelWindowEventHandlerTest() {} virtual ~ToplevelWindowEventHandlerTest() {} - virtual void SetUp() OVERRIDE { - AshTestBase::SetUp(); - parent_ = new aura::Window(NULL); - parent_->Init(ui::LAYER_NOT_DRAWN); - parent_->Show(); - Shell::GetPrimaryRootWindow()->AddChild(parent_); - parent_->SetBounds(Shell::GetPrimaryRootWindow()->bounds()); - handler_.reset(new ToplevelWindowEventHandler(parent_)); - parent_->AddPreTargetHandler(handler_.get()); - } - - virtual void TearDown() OVERRIDE { - parent_->RemovePreTargetHandler(handler_.get()); - handler_.reset(); - parent_ = NULL; - AshTestBase::TearDown(); - } - protected: aura::Window* CreateWindow(int hittest_code) { TestWindowDelegate* d1 = new TestWindowDelegate(hittest_code); aura::Window* w1 = new aura::Window(d1); w1->set_id(1); w1->Init(ui::LAYER_TEXTURED); - parent_->AddChild(w1); + aura::Window* parent = + Shell::GetContainer(Shell::GetPrimaryRootWindow(), + internal::kShellWindowId_AlwaysOnTopContainer); + parent->AddChild(w1); w1->SetBounds(gfx::Rect(0, 0, 100, 100)); w1->Show(); return w1; @@ -114,9 +100,6 @@ class ToplevelWindowEventHandlerTest : public AshTestBase { scoped_ptr<ToplevelWindowEventHandler> handler_; private: - // Window |handler_| is installed on. Owned by RootWindow. - aura::Window* parent_; - DISALLOW_COPY_AND_ASSIGN(ToplevelWindowEventHandlerTest); }; @@ -513,12 +496,7 @@ TEST_F(ToplevelWindowEventHandlerTest, GestureDragToRestore) { #define MAYBE_EscapeReverts EscapeReverts #endif TEST_F(ToplevelWindowEventHandlerTest, MAYBE_EscapeReverts) { - aura::RootWindow* root = Shell::GetPrimaryRootWindow(); - aura::client::ActivationClient* original_client = - aura::client::GetActivationClient(root); - aura::test::TestActivationClient activation_client(root); scoped_ptr<aura::Window> target(CreateWindow(HTBOTTOMRIGHT)); - target->Focus(); aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), target.get()); generator.PressLeftButton(); @@ -531,7 +509,6 @@ TEST_F(ToplevelWindowEventHandlerTest, MAYBE_EscapeReverts) { generator.PressKey(ui::VKEY_ESCAPE, 0); generator.ReleaseKey(ui::VKEY_ESCAPE, 0); EXPECT_EQ("0,0 100x100", target->bounds().ToString()); - aura::client::SetActivationClient(root, original_client); } // Verifies window minimization/maximization completes drag. diff --git a/ash/wm/window_manager_unittest.cc b/ash/wm/window_manager_unittest.cc index dcfabfb..98568e4 100644 --- a/ash/wm/window_manager_unittest.cc +++ b/ash/wm/window_manager_unittest.cc @@ -25,6 +25,7 @@ #include "ui/base/hit_test.h" #include "ui/gfx/screen.h" #include "ui/views/corewm/compound_event_filter.h" +#include "ui/views/corewm/corewm_switches.h" #include "ui/views/corewm/input_method_event_filter.h" namespace { @@ -233,7 +234,7 @@ TEST_F(WindowManagerTest, ActivateOnMouse) { d1.SetWindow(w1.get()); test::TestActivationDelegate d2; scoped_ptr<aura::Window> w2(CreateTestWindowInShellWithDelegate( - &wd, -1, gfx::Rect(70, 70, 50, 50))); + &wd, -2, gfx::Rect(70, 70, 50, 50))); d2.SetWindow(w2.get()); aura::client::FocusClient* focus_client = @@ -289,7 +290,8 @@ TEST_F(WindowManagerTest, ActivateOnMouse) { d1.set_activate(true); w2.reset(); EXPECT_EQ(0, d2.activated_count()); - EXPECT_EQ(0, d2.lost_active_count()); + EXPECT_EQ(views::corewm::UseFocusController() ? 1 : 0, + d2.lost_active_count()); EXPECT_TRUE(wm::IsActiveWindow(w1.get())); EXPECT_EQ(w1.get(), focus_client->GetFocusedWindow()); EXPECT_EQ(1, d1.activated_count()); @@ -299,7 +301,7 @@ TEST_F(WindowManagerTest, ActivateOnMouse) { // focus from the child. { scoped_ptr<aura::Window> w11(CreateTestWindowWithDelegate( - &wd, -1, gfx::Rect(10, 10, 10, 10), w1.get())); + &wd, -11, gfx::Rect(10, 10, 10, 10), w1.get())); aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), w11.get()); // First set the focus to the child |w11|. @@ -404,7 +406,8 @@ TEST_F(WindowManagerTest, ActivateOnTouch) { d1.set_activate(true); w2.reset(); EXPECT_EQ(0, d2.activated_count()); - EXPECT_EQ(0, d2.lost_active_count()); + EXPECT_EQ(views::corewm::UseFocusController() ? 1 : 0, + d2.lost_active_count()); EXPECT_TRUE(wm::IsActiveWindow(w1.get())); EXPECT_EQ(w1.get(), focus_client->GetFocusedWindow()); EXPECT_EQ(1, d1.activated_count()); diff --git a/ui/views/bubble/bubble_delegate.cc b/ui/views/bubble/bubble_delegate.cc index 3e15b85..844598e 100644 --- a/ui/views/bubble/bubble_delegate.cc +++ b/ui/views/bubble/bubble_delegate.cc @@ -196,6 +196,7 @@ NonClientFrameView* BubbleDelegateView::CreateNonClientFrameView( void BubbleDelegateView::OnWidgetClosing(Widget* widget) { if (anchor_widget() == widget) { + anchor_widget_->RemoveObserver(this); anchor_view_ = NULL; anchor_widget_ = NULL; } diff --git a/ui/views/corewm/base_focus_rules.cc b/ui/views/corewm/base_focus_rules.cc index d8b7ed1..2ef30f6 100644 --- a/ui/views/corewm/base_focus_rules.cc +++ b/ui/views/corewm/base_focus_rules.cc @@ -69,6 +69,12 @@ bool BaseFocusRules::CanActivateWindow(aura::Window* window) const { return false; } + // A window must be focusable to be activatable. We don't call + // CanFocusWindow() from here because it will call back to us via + // GetActivatableWindow(). + if (!window->CanFocus()) + return false; + // The window cannot be blocked by a modal transient. return !GetModalTransient(window); } @@ -106,6 +112,14 @@ aura::Window* BaseFocusRules::GetActivatableWindow(aura::Window* window) const { if (CanActivateWindow(child)) return child; + // CanActivateWindow() above will return false if |child| is blocked by a + // modal transient. In this case the modal is or contains the activatable + // window. We recurse because the modal may itself be blocked by a modal + // transient. + aura::Window* modal_transient = GetModalTransient(child); + if (modal_transient) + return GetActivatableWindow(modal_transient); + if (child->transient_parent()) return GetActivatableWindow(child->transient_parent()); @@ -122,8 +136,15 @@ aura::Window* BaseFocusRules::GetFocusableWindow(aura::Window* window) const { // |window| may be in a hierarchy that is non-activatable, in which case we // need to cut over to the activatable hierarchy. aura::Window* activatable = GetActivatableWindow(window); - if (!activatable) - return GetFocusedWindow(window); + if (!activatable) { + // There may not be a related activatable hierarchy to cut over to, in which + // case we try an unrelated one. + aura::Window* toplevel = GetToplevelWindow(window); + if (toplevel) + activatable = GetNextActivatableWindow(toplevel); + if (!activatable) + return NULL; + } if (!activatable->Contains(window)) { // If there's already a child window focused in the activatable hierarchy, diff --git a/ui/views/corewm/focus_controller.cc b/ui/views/corewm/focus_controller.cc index c296385..cb6b278 100644 --- a/ui/views/corewm/focus_controller.cc +++ b/ui/views/corewm/focus_controller.cc @@ -38,6 +38,7 @@ void StackTransientParentsBelowModalWindow(aura::Window* window) { FocusController::FocusController(FocusRules* rules) : active_window_(NULL), focused_window_(NULL), + updating_focus_(false), rules_(rules), ALLOW_THIS_IN_INITIALIZER_LIST(observer_manager_(this)) { DCHECK(rules); @@ -107,14 +108,29 @@ void FocusController::RemoveObserver( void FocusController::FocusWindow(aura::Window* window, const ui::Event* event) { + if (updating_focus_) + return; + + if (window && + (window->Contains(focused_window_) || window->Contains(active_window_))) { + return; + } + // Focusing a window also activates its containing activatable window. Note // that the rules could redirect activation activation and/or focus. aura::Window* focusable = rules_->GetFocusableWindow(window); aura::Window* activatable = focusable ? rules_->GetActivatableWindow(focusable) : NULL; + + // We need valid focusable/activatable windows in the event we're not clearing + // focus. "Clearing focus" is inferred by whether or not |window| passed to + // this function is non-NULL. + if (window && (!focusable || !activatable)) + return; + DCHECK((focusable && activatable) || !window); SetActiveWindow(activatable); - if (focusable && activatable) - DCHECK(GetActiveWindow()->Contains(focusable)); + if (active_window_) + DCHECK(active_window_->Contains(focusable)); SetFocusedWindow(focusable); } @@ -195,12 +211,13 @@ void FocusController::OnWindowInitialized(aura::Window* window) { // FocusController, private: void FocusController::SetFocusedWindow(aura::Window* window) { - if (window == focused_window_) + if (updating_focus_ || window == focused_window_) return; DCHECK(rules_->CanFocusWindow(window)); if (window) DCHECK_EQ(window, rules_->GetFocusableWindow(window)); + base::AutoReset<bool> updating_focus(&updating_focus_, true); aura::Window* lost_focus = focused_window_; focused_window_ = window; @@ -217,12 +234,14 @@ void FocusController::SetFocusedWindow(aura::Window* window) { } void FocusController::SetActiveWindow(aura::Window* window) { - if (window == active_window_) + if (updating_focus_ || window == active_window_) return; + DCHECK(rules_->CanActivateWindow(window)); if (window) DCHECK_EQ(window, rules_->GetActivatableWindow(window)); + base::AutoReset<bool> updating_focus(&updating_focus_, true); aura::Window* lost_activation = active_window_; active_window_ = window; if (active_window_) { @@ -244,12 +263,15 @@ void FocusController::SetActiveWindow(aura::Window* window) { void FocusController::WindowLostFocusFromDispositionChange( aura::Window* window) { + // A window's modality state will interfere with focus restoration during its + // destruction. + window->ClearProperty(aura::client::kModalKey); // TODO(beng): See if this function can be replaced by a call to // FocusWindow(). // Activation adjustments are handled first in the event of a disposition // changed. If an activation change is necessary, focus is reset as part of // that process so there's no point in updating focus independently. - if (window->Contains(active_window_)) { + if (window == active_window_) { aura::Window* next_activatable = rules_->GetNextActivatableWindow(window); SetActiveWindow(next_activatable); SetFocusedWindow(next_activatable); diff --git a/ui/views/corewm/focus_controller.h b/ui/views/corewm/focus_controller.h index df9b51e..a870c7c 100644 --- a/ui/views/corewm/focus_controller.h +++ b/ui/views/corewm/focus_controller.h @@ -106,6 +106,8 @@ class VIEWS_EXPORT FocusController : public aura::client::ActivationClient, aura::Window* active_window_; aura::Window* focused_window_; + bool updating_focus_; + scoped_ptr<FocusRules> rules_; ObserverList<aura::client::ActivationChangeObserver> activation_observers_; diff --git a/ui/views/corewm/focus_controller_unittest.cc b/ui/views/corewm/focus_controller_unittest.cc index a74346d..01b1462 100644 --- a/ui/views/corewm/focus_controller_unittest.cc +++ b/ui/views/corewm/focus_controller_unittest.cc @@ -73,6 +73,55 @@ class ScopedFocusNotificationObserver : public FocusNotificationObserver { DISALLOW_COPY_AND_ASSIGN(ScopedFocusNotificationObserver); }; +// Focus/Activation change observer that attempts to shift focus/activation +// while processing an update to focus/activation. +class RecurseFocusObserver : public aura::client::ActivationChangeObserver, + public aura::client::FocusChangeObserver { + public: + explicit RecurseFocusObserver(aura::Window* other) : other_(other) {} + virtual ~RecurseFocusObserver() {} + + private: + // Overridden from aura::client::ActivationChangeObserver: + virtual void OnWindowActivated(aura::Window* gained_active, + aura::Window* lost_active) OVERRIDE { + DCHECK_NE(gained_active, other_); + aura::client::GetActivationClient(other_->GetRootWindow())->ActivateWindow( + other_); + } + + // Overridden from aura::client::FocusChangeObserver: + virtual void OnWindowFocused(aura::Window* gained_focus, + aura::Window* lost_focus) OVERRIDE { + DCHECK_NE(gained_focus, other_); + aura::client::GetFocusClient(other_)->FocusWindow(other_, NULL); + } + + aura::Window* other_; + + DISALLOW_COPY_AND_ASSIGN(RecurseFocusObserver); +}; + +class ScopedRecurseFocusObserver : public RecurseFocusObserver { + public: + ScopedRecurseFocusObserver(aura::RootWindow* root_window, + aura::Window* other) + : RecurseFocusObserver(other), + root_window_(root_window) { + aura::client::GetActivationClient(root_window_)->AddObserver(this); + aura::client::GetFocusClient(root_window_)->AddObserver(this); + } + virtual ~ScopedRecurseFocusObserver() { + aura::client::GetActivationClient(root_window_)->RemoveObserver(this); + aura::client::GetFocusClient(root_window_)->RemoveObserver(this); + } + + private: + aura::RootWindow* root_window_; + + DISALLOW_COPY_AND_ASSIGN(ScopedRecurseFocusObserver); +}; + class ScopedTargetFocusNotificationObserver : public FocusNotificationObserver { public: ScopedTargetFocusNotificationObserver(aura::RootWindow* root_window, int id) @@ -248,8 +297,11 @@ class FocusControllerTestBase : public aura::test::AuraTestBase { virtual void DuplicateActivationEvents() {} virtual void ShiftFocusWithinActiveWindow() {} virtual void ShiftFocusToChildOfInactiveWindow() {} + virtual void ShiftFocusToParentOfFocusedWindow() {} virtual void FocusRulesOverride() = 0; virtual void ActivationRulesOverride() = 0; + virtual void NoRecurseFocus() {} + virtual void NoRecurseActivation() {} private: scoped_ptr<FocusController> focus_controller_; @@ -390,6 +442,15 @@ class FocusControllerDirectTestBase : public FocusControllerTestBase { EXPECT_EQ(1, GetActiveWindowId()); EXPECT_EQ(11, GetFocusedWindowId()); } + virtual void ShiftFocusToParentOfFocusedWindow() OVERRIDE { + ActivateWindowById(1); + EXPECT_EQ(1, GetFocusedWindowId()); + FocusWindowById(11); + EXPECT_EQ(11, GetFocusedWindowId()); + FocusWindowById(1); + // Focus should _not_ shift to the parent of the already-focused window. + EXPECT_EQ(11, GetFocusedWindowId()); + } virtual void FocusRulesOverride() OVERRIDE { EXPECT_EQ(NULL, GetFocusedWindow()); FocusWindowById(11); @@ -421,6 +482,22 @@ class FocusControllerDirectTestBase : public FocusControllerTestBase { EXPECT_EQ(2, GetActiveWindowId()); EXPECT_EQ(2, GetFocusedWindowId()); } + virtual void NoRecurseFocus() OVERRIDE { + aura::Window* w2 = root_window()->GetChildById(2); + ScopedRecurseFocusObserver observer(root_window(), w2); + FocusWindowById(1); + // |observer| will try to set active to w2, but the focus system should + // prevent recursive updating. + EXPECT_EQ(1, GetFocusedWindowId()); + } + virtual void NoRecurseActivation() OVERRIDE { + aura::Window* w2 = root_window()->GetChildById(2); + ScopedRecurseFocusObserver observer(root_window(), w2); + ActivateWindowById(1); + // |observer| will try to set active to w2, but the focus system should + // prevent recursive updating. + EXPECT_EQ(1, GetActiveWindowId()); + } private: DISALLOW_COPY_AND_ASSIGN(FocusControllerDirectTestBase); @@ -792,11 +869,20 @@ DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusWithinActiveWindow); // activation to the activatable parent and focuses the child. DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusToChildOfInactiveWindow); +// - Input events/API calls to focus the parent of the focused window do not +// shift focus away from the child. +DIRECT_FOCUS_CHANGE_TESTS(ShiftFocusToParentOfFocusedWindow); + // - Verifies that FocusRules determine what can be focused. ALL_FOCUS_TESTS(FocusRulesOverride); // - Verifies that FocusRules determine what can be activated. TARGET_FOCUS_TESTS(ActivationRulesOverride); +// - Verifies that attempts to change focus or activation from a focus or +// activation change observer are ignored. +DIRECT_FOCUS_CHANGE_TESTS(NoRecurseFocus); +DIRECT_FOCUS_CHANGE_TESTS(NoRecurseActivation); + } // namespace corewm } // namespace views diff --git a/ui/views/corewm/window_modality_controller.cc b/ui/views/corewm/window_modality_controller.cc index 57bbe3c..907c823 100644 --- a/ui/views/corewm/window_modality_controller.cc +++ b/ui/views/corewm/window_modality_controller.cc @@ -120,11 +120,29 @@ ui::EventResult WindowModalityController::OnTouchEvent(ui::TouchEvent* event) { ui::ER_UNHANDLED; } +//////////////////////////////////////////////////////////////////////////////// +// WindowModalityController, aura::EnvObserver implementation: + void WindowModalityController::OnWindowInitialized(aura::Window* window) { windows_.push_back(window); window->AddObserver(this); } +//////////////////////////////////////////////////////////////////////////////// +// WindowModalityController, aura::WindowObserver implementation: + +void WindowModalityController::OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) { + // In tests, we sometimes create the modality relationship after a window is + // visible. + if (key == aura::client::kModalKey && + window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE && + window->IsVisible()) { + ActivateWindow(window); + } +} + void WindowModalityController::OnWindowVisibilityChanged( aura::Window* window, bool visible) { diff --git a/ui/views/corewm/window_modality_controller.h b/ui/views/corewm/window_modality_controller.h index 9384197..449a894 100644 --- a/ui/views/corewm/window_modality_controller.h +++ b/ui/views/corewm/window_modality_controller.h @@ -46,6 +46,9 @@ class VIEWS_EXPORT WindowModalityController : public ui::EventHandler, virtual void OnWindowInitialized(aura::Window* window) OVERRIDE; // Overridden from aura::WindowObserver: + virtual void OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) OVERRIDE; virtual void OnWindowVisibilityChanged(aura::Window* window, bool visible) OVERRIDE; virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE; |