diff options
author | mtomasz@chromium.org <mtomasz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-17 04:30:56 +0000 |
---|---|---|
committer | mtomasz@chromium.org <mtomasz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-17 04:30:56 +0000 |
commit | 6b58b286091525e14c29f79a00c2682b2f71462f (patch) | |
tree | d1dcbcd599be4d3eec49d526e66c4ee840826910 /ash | |
parent | f30e3dac09ae32a4d985b6018ef4f0a71257b776 (diff) | |
download | chromium_src-6b58b286091525e14c29f79a00c2682b2f71462f.zip chromium_src-6b58b286091525e14c29f79a00c2682b2f71462f.tar.gz chromium_src-6b58b286091525e14c29f79a00c2682b2f71462f.tar.bz2 |
Yet another approach. Not pretty, but simple and works.
BUG=156772
Review URL: https://chromiumcodereview.appspot.com/11451002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@173417 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r-- | ash/ash.gyp | 1 | ||||
-rw-r--r-- | ash/launcher/launcher.cc | 27 | ||||
-rw-r--r-- | ash/launcher/launcher.h | 13 | ||||
-rw-r--r-- | ash/launcher/launcher_unittest.cc | 15 | ||||
-rw-r--r-- | ash/wm/ash_activation_controller.cc | 37 | ||||
-rw-r--r-- | ash/wm/ash_activation_controller.h | 8 | ||||
-rw-r--r-- | ash/wm/ash_activation_controller_unittest.cc | 126 |
7 files changed, 221 insertions, 6 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp index 886a963..cac4596 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -580,6 +580,7 @@ 'test/ash_unittests.cc', 'tooltips/tooltip_controller_unittest.cc', 'wm/activation_controller_unittest.cc', + 'wm/ash_activation_controller_unittest.cc', 'wm/base_layout_manager_unittest.cc', 'wm/cursor_manager_unittest.cc', 'wm/custom_frame_view_ash_unittest.cc', diff --git a/ash/launcher/launcher.cc b/ash/launcher/launcher.cc index 8668879..a73f402 100644 --- a/ash/launcher/launcher.cc +++ b/ash/launcher/launcher.cc @@ -19,6 +19,7 @@ #include "ash/wm/shelf_layout_manager.h" #include "ash/wm/window_properties.h" #include "grit/ash_resources.h" +#include "ui/aura/client/activation_client.h" #include "ui/aura/root_window.h" #include "ui/aura/window.h" #include "ui/aura/window_observer.h" @@ -68,9 +69,14 @@ class Launcher::DelegateView : public views::WidgetDelegate, return View::GetWidget(); } virtual bool CanActivate() const OVERRIDE { - // We don't want mouse clicks to activate us, but we need to allow - // activation when the user is using the keyboard (FocusCycler). - return focus_cycler_ && focus_cycler_->widget_activating() == GetWidget(); + // Allow to activate as fallback. + if (launcher_->activating_as_fallback_) + return true; + // Allow to activate from the focus cycler. + if (focus_cycler_ && focus_cycler_->widget_activating() == GetWidget()) + return true; + // Disallow activating in other cases, especially when using mouse. + return false; } // BackgroundAnimatorDelegate overrides: @@ -209,7 +215,8 @@ Launcher::Launcher(LauncherModel* launcher_model, launcher_view_(NULL), alignment_(SHELF_ALIGNMENT_BOTTOM), delegate_(launcher_delegate), - background_animator_(delegate_view_, 0, kLauncherBackgroundAlpha) { + background_animator_(delegate_view_, 0, kLauncherBackgroundAlpha), + activating_as_fallback_(false) { widget_.reset(new views::Widget); views::Widget::InitParams params( views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); @@ -236,9 +243,12 @@ Launcher::Launcher(LauncherModel* launcher_model, gfx::Size pref = static_cast<views::View*>(launcher_view_)->GetPreferredSize(); widget_->SetBounds(gfx::Rect(pref)); + + widget_->AddObserver(this); } Launcher::~Launcher() { + widget_->RemoveObserver(this); } // static @@ -406,6 +416,15 @@ void Launcher::SwitchToWindow(int window_index) { } } +void Launcher::OnWidgetActivationChanged(views::Widget* widget, bool active) { + activating_as_fallback_ = false; + if (active) { + delegate_view_->SetPaneFocusAndFocusDefault(); + } else { + delegate_view_->GetFocusManager()->ClearFocus(); + } +} + internal::LauncherView* Launcher::GetLauncherViewForTest() { return launcher_view_; } diff --git a/ash/launcher/launcher.h b/ash/launcher/launcher.h index 03de4ec..a934a5b 100644 --- a/ash/launcher/launcher.h +++ b/ash/launcher/launcher.h @@ -12,6 +12,7 @@ #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "ui/gfx/size.h" +#include "ui/views/widget/widget_observer.h" namespace aura { class Window; @@ -38,7 +39,7 @@ class LauncherIconObserver; class LauncherDelegate; class LauncherModel; -class ASH_EXPORT Launcher { +class ASH_EXPORT Launcher: public views::WidgetObserver { public: Launcher(LauncherModel* launcher_model, LauncherDelegate* launcher_delegate, @@ -124,6 +125,13 @@ class ASH_EXPORT Launcher { aura::Window* window_container() { return window_container_; } + // Called by the activation delegate, before the launcher is activated + // when no other windows are visible. + void WillActivateAsFallback() { activating_as_fallback_ = true; } + + // Overridden from views::WidgetObserver: + void OnWidgetActivationChanged(views::Widget* widget, bool active) OVERRIDE; + private: class DelegateView; @@ -149,6 +157,9 @@ class ASH_EXPORT Launcher { // Used to animate the background. internal::BackgroundAnimator background_animator_; + // Used then activation is forced from the activation delegate. + bool activating_as_fallback_; + DISALLOW_COPY_AND_ASSIGN(Launcher); }; diff --git a/ash/launcher/launcher_unittest.cc b/ash/launcher/launcher_unittest.cc index 2c3f8a8..ea9135b 100644 --- a/ash/launcher/launcher_unittest.cc +++ b/ash/launcher/launcher_unittest.cc @@ -10,6 +10,7 @@ #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/launcher_view_test_api.h" +#include "ash/wm/window_util.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" @@ -77,4 +78,18 @@ TEST_F(LauncherTest, OpenBrowser) { ASSERT_EQ(--button_count, test.GetButtonCount()); } +// Launcher can't be activated on mouse click, but it is activable from +// the focus cycler or as fallback. +TEST_F(LauncherTest, ActivateAsFallback) { + Launcher* launcher = Launcher::ForPrimaryDisplay(); + views::Widget* launcher_widget = launcher->widget(); + EXPECT_FALSE(launcher_widget->CanActivate()); + + launcher->WillActivateAsFallback(); + EXPECT_TRUE(launcher_widget->CanActivate()); + + wm::ActivateWindow(launcher_widget->GetNativeWindow()); + EXPECT_FALSE(launcher_widget->CanActivate()); +} + } // namespace ash diff --git a/ash/wm/ash_activation_controller.cc b/ash/wm/ash_activation_controller.cc index f9cc006..261bd62 100644 --- a/ash/wm/ash_activation_controller.cc +++ b/ash/wm/ash_activation_controller.cc @@ -4,13 +4,16 @@ #include "ash/wm/ash_activation_controller.h" +#include "ash/launcher/launcher.h" #include "ash/root_window_controller.h" #include "ash/shell.h" +#include "ash/shell_delegate.h" #include "ash/wm/activation_controller.h" #include "ash/wm/property_util.h" #include "ash/wm/window_util.h" #include "ash/wm/workspace_controller.h" #include "ui/views/corewm/window_modality_controller.h" +#include "ui/views/widget/widget.h" namespace ash { namespace internal { @@ -34,6 +37,10 @@ aura::Window* AshActivationController::WillActivateWindow( if (window_modal_transient) return window_modal_transient; + // Fallback to launcher + if (!window) + window = PrepareToActivateLauncher(); + // Make sure the workspace manager switches to the workspace for window. // Without this CanReceiveEvents() below returns false and activation never // changes. CanReceiveEvents() returns false if |window| isn't in the active @@ -77,5 +84,35 @@ aura::Window* AshActivationController::WillFocusWindow( return window; } +aura::Window* AshActivationController::PrepareToActivateLauncher() { + // If workspace controller is not available, then it means that the root + // window is being destroyed. We can't activate any window then. + if (!GetRootWindowController( + Shell::GetActiveRootWindow())->workspace_controller()) { + return NULL; + } + // Fallback to a launcher only when Spoken feedback is enabled. + if (!Shell::GetInstance()->delegate()->IsSpokenFeedbackEnabled()) + return NULL; + Launcher* launcher; + if (Shell::IsLauncherPerDisplayEnabled()) { + launcher = GetRootWindowController( + Shell::GetActiveRootWindow())->launcher(); + } else { + launcher = Launcher::ForPrimaryDisplay(); + } + // Launcher is not always available, eg. not in the login screen. + if (!launcher) + return NULL; + views::Widget* launcher_widget = launcher->widget(); + // Launcher's window may be already destroyed in shutting down process. + if (!launcher_widget) + return NULL; + aura::Window* launcher_window = launcher_widget->GetNativeWindow(); + // Notify launcher to allow activation via CanActivate(). + launcher->WillActivateAsFallback(); + return launcher_window; +} + } // namespace internal } // namespace ash diff --git a/ash/wm/ash_activation_controller.h b/ash/wm/ash_activation_controller.h index 0e9be46..c3961f9 100644 --- a/ash/wm/ash_activation_controller.h +++ b/ash/wm/ash_activation_controller.h @@ -5,6 +5,7 @@ #ifndef ASH_WM_ASH_ACTIVATION_CONTROLLER_H_ #define ASH_WM_ASH_ACTIVATION_CONTROLLER_H_ +#include "ash/ash_export.h" #include "ash/wm/activation_controller_delegate.h" #include "base/compiler_specific.h" #include "base/basictypes.h" @@ -12,7 +13,7 @@ namespace ash { namespace internal { -class AshActivationController : public ActivationControllerDelegate { +class ASH_EXPORT AshActivationController : public ActivationControllerDelegate { public: AshActivationController(); virtual ~AshActivationController(); @@ -22,6 +23,11 @@ class AshActivationController : public ActivationControllerDelegate { virtual aura::Window* WillActivateWindow(aura::Window* window) OVERRIDE; virtual aura::Window* WillFocusWindow(aura::Window* window) OVERRIDE; + // Returns a handle to the launcher on the active root window which will + // be activated as fallback. Also notifies the launcher, so it can return + // true from Launcher::CanActivate(). + aura::Window* PrepareToActivateLauncher(); + DISALLOW_COPY_AND_ASSIGN(AshActivationController); }; diff --git a/ash/wm/ash_activation_controller_unittest.cc b/ash/wm/ash_activation_controller_unittest.cc new file mode 100644 index 0000000..3fc31df --- /dev/null +++ b/ash/wm/ash_activation_controller_unittest.cc @@ -0,0 +1,126 @@ +// Copyright (c) 2012 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/wm/ash_activation_controller.h" + +#include "ash/launcher/launcher.h" +#include "ash/root_window_controller.h" +#include "ash/shell_delegate.h" +#include "ash/test/ash_test_base.h" +#include "ash/wm/property_util.h" +#include "ash/wm/window_util.h" +#include "ui/aura/window.h" + +namespace ash { + +namespace wm { + +namespace { + +class AshActivationControllerTest : public test::AshTestBase { + public: + AshActivationControllerTest() + : launcher_(NULL), launcher_widget_(NULL), launcher_window_(NULL) {} + virtual ~AshActivationControllerTest() {} + + virtual void SetUp() OVERRIDE { + test::AshTestBase::SetUp(); + ash_activation_controller_.reset(new internal::AshActivationController()); + launcher_ = Launcher::ForPrimaryDisplay(); + ASSERT_TRUE(launcher_); + launcher_widget_ = launcher_->widget(); + ASSERT_TRUE(launcher_widget_); + launcher_window_ = launcher_widget_->GetNativeWindow(); + ASSERT_TRUE(launcher_window_); + } + + void SetSpokenFeedbackState(bool enabled) { + if (Shell::GetInstance()->delegate()->IsSpokenFeedbackEnabled() != + enabled) { + Shell::GetInstance()->delegate()->ToggleSpokenFeedback( + A11Y_NOTIFICATION_NONE); + } + } + + protected: + scoped_ptr<internal::ActivationControllerDelegate> ash_activation_controller_; + ash::Launcher* launcher_; + views::Widget* launcher_widget_; + aura::Window* launcher_window_; + + DISALLOW_COPY_AND_ASSIGN(AshActivationControllerTest); +}; + +TEST_F(AshActivationControllerTest, LauncherFallback) { + // When spoken feedback is disabled, then fallback should not occur. + { + SetSpokenFeedbackState(false); + aura::Window* result = ash_activation_controller_->WillActivateWindow(NULL); + EXPECT_EQ(NULL, result); + } + + // When spoken feedback is enabled, then fallback should occur. + { + SetSpokenFeedbackState(true); + aura::Window* result = ash_activation_controller_->WillActivateWindow(NULL); + EXPECT_EQ(launcher_window_, result); + } + + // No fallback when activating another window. + { + aura::Window* test_window = CreateTestWindowInShellWithId(0); + aura::Window* result = ash_activation_controller_-> + WillActivateWindow(test_window); + EXPECT_EQ(test_window, result); + } +} + +TEST_F(AshActivationControllerTest, LauncherFallbackOnShutdown) { + SetSpokenFeedbackState(true); + // While shutting down a root window controller, activation controller + // is notified about destroyed windows and therefore will try to activate + // a launcher as fallback, which would result in segmentation faults since + // the launcher's window or the workspace's controller may be already + // destroyed. + GetRootWindowController(Shell::GetActiveRootWindow())->CloseChildWindows(); + + aura::Window* result = ash_activation_controller_->WillActivateWindow(NULL); + EXPECT_EQ(NULL, result); +} + +TEST_F(AshActivationControllerTest, LauncherEndToEndFallbackOnDestroyTest) { + // This test checks the whole fallback activation flow. + SetSpokenFeedbackState(true); + + scoped_ptr<aura::Window> test_window(CreateTestWindowInShellWithId(0)); + ActivateWindow(test_window.get()); + ASSERT_EQ(test_window.get(), GetActiveWindow()); + + // Close the window. + test_window.reset(); + + // Verify if the launcher got activated as fallback. + ASSERT_EQ(launcher_window_, GetActiveWindow()); +} + +TEST_F(AshActivationControllerTest, LauncherEndToEndFallbackOnMinimizeTest) { + // This test checks the whole fallback activation flow. + SetSpokenFeedbackState(true); + + scoped_ptr<aura::Window> test_window(CreateTestWindowInShellWithId(0)); + ActivateWindow(test_window.get()); + ASSERT_EQ(test_window.get(), GetActiveWindow()); + + // Minimize the window. + MinimizeWindow(test_window.get()); + + // Verify if the launcher got activated as fallback. + ASSERT_EQ(launcher_window_, GetActiveWindow()); +} + +} // namespace + +} // namespace wm + +} // namespace ash |