diff options
author | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-24 13:23:04 +0000 |
---|---|---|
committer | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-24 13:23:04 +0000 |
commit | 339e312781ed3be0e10a79d9c8855dcb110154d5 (patch) | |
tree | e4489415c3b43a9657ad3b959848e6d689c42c99 | |
parent | a306aaae14d5c582d8f0916624e9c7819df7dee4 (diff) | |
download | chromium_src-339e312781ed3be0e10a79d9c8855dcb110154d5.zip chromium_src-339e312781ed3be0e10a79d9c8855dcb110154d5.tar.gz chromium_src-339e312781ed3be0e10a79d9c8855dcb110154d5.tar.bz2 |
Refactor and move ash independent accelerator handling code in nested loop to ui/wm/core
I also renamed classes to NestedAcceleratorXxx. I felt this is a bit more clearer than NestedDispatcher, especially in ui/wm/core. Please let me know if you disagree or have better suggestion. I'm happy to rename them.
BUG=None
Review URL: https://codereview.chromium.org/298703007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@272740 0039d316-1c4b-4281-b951-d872f2087c98
17 files changed, 440 insertions, 286 deletions
diff --git a/ash/accelerators/accelerator_dispatcher.h b/ash/accelerators/accelerator_dispatcher.h deleted file mode 100644 index 72b5df7..0000000 --- a/ash/accelerators/accelerator_dispatcher.h +++ /dev/null @@ -1,58 +0,0 @@ -// 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. - -#ifndef ASH_ACCELERATORS_ACCELERATOR_DISPATCHER_H_ -#define ASH_ACCELERATORS_ACCELERATOR_DISPATCHER_H_ - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" - -namespace base { -class MessagePumpDispatcher; -class RunLoop; -} - -namespace ui { -class KeyEvent; -} - -namespace ash { - -// Dispatcher for handling accelerators from menu. -// -// Wraps a nested dispatcher to which control is passed if no accelerator key -// has been pressed. If the nested dispatcher is NULL, then the control is -// passed back to the default dispatcher. -// TODO(pkotwicz): Add support for a |nested_dispatcher| which sends -// events to a system IME. -class ASH_EXPORT AcceleratorDispatcher { - public: - virtual ~AcceleratorDispatcher() {} - - static scoped_ptr<AcceleratorDispatcher> Create( - base::MessagePumpDispatcher* nested_dispatcher); - - // Creates a base::RunLoop object to run a nested message loop. - virtual scoped_ptr<base::RunLoop> CreateRunLoop() = 0; - - protected: - AcceleratorDispatcher() {} - - // Closes any open menu if the key-event could potentially be a system - // accelerator. - // Returns whether a menu was closed. - bool MenuClosedForPossibleAccelerator(const ui::KeyEvent& key_event); - - // Attempts to trigger an accelerator for the key-event. - // Returns whether an accelerator was triggered. - bool AcceleratorProcessedForKeyEvent(const ui::KeyEvent& key_event); - - private: - DISALLOW_COPY_AND_ASSIGN(AcceleratorDispatcher); -}; - -} // namespace ash - -#endif // ASH_ACCELERATORS_ACCELERATOR_DISPATCHER_H_ diff --git a/ash/accelerators/accelerator_dispatcher.cc b/ash/accelerators/nested_accelerator_delegate.cc index fe194f3..eb83a21 100644 --- a/ash/accelerators/accelerator_dispatcher.cc +++ b/ash/accelerators/nested_accelerator_delegate.cc @@ -1,8 +1,8 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 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/accelerators/accelerator_dispatcher.h" +#include "ash/accelerators/nested_accelerator_delegate.h" #include "ash/accelerators/accelerator_controller.h" #include "ash/shell.h" @@ -35,21 +35,28 @@ bool IsPossibleAcceleratorNotForMenu(const ui::KeyEvent& key_event) { } // namespace -bool AcceleratorDispatcher::MenuClosedForPossibleAccelerator( +NestedAcceleratorDelegate::NestedAcceleratorDelegate() { + LOG(ERROR) << "NAD"; +} + +NestedAcceleratorDelegate::~NestedAcceleratorDelegate() { + LOG(ERROR) << "~NAD"; +} + +bool NestedAcceleratorDelegate::ShouldProcessEventNow( const ui::KeyEvent& key_event) { if (!IsPossibleAcceleratorNotForMenu(key_event)) - return false; + return true; if (views::MenuController* menu_controller = views::MenuController::GetActiveInstance()) { menu_controller->CancelAll(); - return true; + return false; } - return false; + return true; } -bool AcceleratorDispatcher::AcceleratorProcessedForKeyEvent( - const ui::KeyEvent& key_event) { +bool NestedAcceleratorDelegate::ProcessEvent(const ui::KeyEvent& key_event) { ash::AcceleratorController* accelerator_controller = ash::Shell::GetInstance()->accelerator_controller(); if (!accelerator_controller) diff --git a/ash/accelerators/nested_accelerator_delegate.h b/ash/accelerators/nested_accelerator_delegate.h new file mode 100644 index 0000000..63bc498 --- /dev/null +++ b/ash/accelerators/nested_accelerator_delegate.h @@ -0,0 +1,28 @@ +// Copyright 2014 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_ACCELERATORS_NESTED_ACCELERATOR_DELEGATE_H_ +#define ASH_ACCELERATORS_NESTED_ACCELERATOR_DELEGATE_H_ + +#include "base/macros.h" +#include "ui/wm/core/nested_accelerator_delegate.h" + +namespace ash { + +class NestedAcceleratorDelegate : public wm::NestedAcceleratorDelegate { + public: + NestedAcceleratorDelegate(); + virtual ~NestedAcceleratorDelegate(); + + // wm::AcceleratorDispatcher::Delegate + virtual bool ShouldProcessEventNow(const ui::KeyEvent& key_event) OVERRIDE; + virtual bool ProcessEvent(const ui::KeyEvent& key_event) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(NestedAcceleratorDelegate); +}; + +} // namespace + +#endif // ASH_ACCELERATORS_NESTED_ACCELERATOR_DELEGATE_H_ diff --git a/ash/accelerators/nested_dispatcher_controller_unittest.cc b/ash/accelerators/nested_dispatcher_controller_unittest.cc deleted file mode 100644 index e5aef88..0000000 --- a/ash/accelerators/nested_dispatcher_controller_unittest.cc +++ /dev/null @@ -1,151 +0,0 @@ -// 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/accelerators/accelerator_controller.h" -#include "ash/session/session_state_delegate.h" -#include "ash/shell.h" -#include "ash/shell_window_ids.h" -#include "ash/test/ash_test_base.h" -#include "base/bind.h" -#include "base/event_types.h" -#include "base/message_loop/message_loop.h" -#include "ui/aura/test/test_windows.h" -#include "ui/aura/window.h" -#include "ui/aura/window_event_dispatcher.h" -#include "ui/base/accelerators/accelerator.h" -#include "ui/events/event_constants.h" -#include "ui/events/event_utils.h" -#include "ui/events/platform/platform_event_dispatcher.h" -#include "ui/events/platform/platform_event_source.h" -#include "ui/events/platform/scoped_event_dispatcher.h" -#include "ui/wm/public/dispatcher_client.h" - -#if defined(USE_X11) -#include <X11/Xlib.h> -#include "ui/events/test/events_test_utils_x11.h" -#endif // USE_X11 - -namespace ash { -namespace test { - -namespace { - -class MockDispatcher : public ui::PlatformEventDispatcher { - public: - MockDispatcher() : num_key_events_dispatched_(0) { - } - - int num_key_events_dispatched() { return num_key_events_dispatched_; } - - private: - // ui::PlatformEventDispatcher: - virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE { - return true; - } - virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE { - if (ui::EventTypeFromNative(event) == ui::ET_KEY_RELEASED) - num_key_events_dispatched_++; - return ui::POST_DISPATCH_NONE; - } - - int num_key_events_dispatched_; - - DISALLOW_COPY_AND_ASSIGN(MockDispatcher); -}; - -class TestTarget : public ui::AcceleratorTarget { - public: - TestTarget() : accelerator_pressed_count_(0) { - } - virtual ~TestTarget() { - } - - int accelerator_pressed_count() const { - return accelerator_pressed_count_; - } - - // Overridden from ui::AcceleratorTarget: - virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE { - accelerator_pressed_count_++; - return true; - } - virtual bool CanHandleAccelerators() const OVERRIDE { - return true; - } - - private: - int accelerator_pressed_count_; - - DISALLOW_COPY_AND_ASSIGN(TestTarget); -}; - -void DispatchKeyReleaseA() { - // Sending both keydown and keyup is necessary here because the accelerator - // manager only checks a keyup event following a keydown event. See - // ShouldHandle() in ui/base/accelerators/accelerator_manager.cc for details. -#if defined(OS_WIN) - MSG native_event_down = { NULL, WM_KEYDOWN, ui::VKEY_A, 0 }; - ash::Shell::GetPrimaryRootWindow()->host()->PostNativeEvent( - native_event_down); - MSG native_event_up = { NULL, WM_KEYUP, ui::VKEY_A, 0 }; - ash::Shell::GetPrimaryRootWindow()->host()->PostNativeEvent(native_event_up); -#elif defined(USE_X11) - ui::ScopedXI2Event native_event; - native_event.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, 0); - aura::WindowTreeHost* host = ash::Shell::GetPrimaryRootWindow()->GetHost(); - host->PostNativeEvent(native_event); - native_event.InitKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_A, 0); - host->PostNativeEvent(native_event); -#endif - // Make sure the inner message-loop terminates after dispatching the events. - base::MessageLoop::current()->PostTask(FROM_HERE, - base::MessageLoop::current()->QuitClosure()); -} - -} // namespace - -typedef AshTestBase NestedDispatcherTest; - -// Aura window above lock screen in z order. -TEST_F(NestedDispatcherTest, AssociatedWindowAboveLockScreen) { - MockDispatcher inner_dispatcher; - - scoped_ptr<aura::Window> mock_lock_container( - CreateTestWindowInShellWithId(0)); - aura::test::CreateTestWindowWithId(1, mock_lock_container.get()); - scoped_ptr<aura::Window> associated_window(CreateTestWindowInShellWithId(2)); - EXPECT_TRUE(aura::test::WindowIsAbove(associated_window.get(), - mock_lock_container.get())); - - DispatchKeyReleaseA(); - aura::Window* root_window = ash::Shell::GetPrimaryRootWindow(); - scoped_ptr<ui::ScopedEventDispatcher> override_dispatcher = - ui::PlatformEventSource::GetInstance()->OverrideDispatcher( - &inner_dispatcher); - aura::client::GetDispatcherClient(root_window)->RunWithDispatcher(NULL); - EXPECT_EQ(1, inner_dispatcher.num_key_events_dispatched()); -} - -// Test that the nested dispatcher handles accelerators. -TEST_F(NestedDispatcherTest, AcceleratorsHandled) { - MockDispatcher inner_dispatcher; - aura::Window* root_window = ash::Shell::GetPrimaryRootWindow(); - - ui::Accelerator accelerator(ui::VKEY_A, ui::EF_NONE); - accelerator.set_type(ui::ET_KEY_RELEASED); - TestTarget target; - Shell::GetInstance()->accelerator_controller()->Register(accelerator, - &target); - - DispatchKeyReleaseA(); - scoped_ptr<ui::ScopedEventDispatcher> override_dispatcher = - ui::PlatformEventSource::GetInstance()->OverrideDispatcher( - &inner_dispatcher); - aura::client::GetDispatcherClient(root_window)->RunWithDispatcher(NULL); - EXPECT_EQ(0, inner_dispatcher.num_key_events_dispatched()); - EXPECT_EQ(1, target.accelerator_pressed_count()); -} - -} // namespace test -} // namespace ash diff --git a/ash/ash.gyp b/ash/ash.gyp index 6d8fece..b42fe07 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -1,4 +1,4 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. +#a 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. @@ -55,10 +55,8 @@ 'accelerators/accelerator_commands.h', 'accelerators/accelerator_controller.cc', 'accelerators/accelerator_controller.h', - 'accelerators/accelerator_dispatcher.cc', - 'accelerators/accelerator_dispatcher.h', - 'accelerators/accelerator_dispatcher_linux.cc', - 'accelerators/accelerator_dispatcher_win.cc', + 'accelerators/nested_accelerator_delegate.cc', + 'accelerators/nested_accelerator_delegate.h', 'accelerators/accelerator_filter.cc', 'accelerators/accelerator_filter.h', 'accelerators/accelerator_table.cc', @@ -73,8 +71,6 @@ 'accelerators/focus_manager_factory.h', 'accelerators/magnifier_key_scroller.cc', 'accelerators/magnifier_key_scroller.h', - 'accelerators/nested_dispatcher_controller.cc', - 'accelerators/nested_dispatcher_controller.h', 'accelerators/spoken_feedback_toggler.cc', 'accelerators/spoken_feedback_toggler.h', 'accelerometer/accelerometer_controller.cc', @@ -920,7 +916,6 @@ 'accelerators/accelerator_filter_unittest.cc', 'accelerators/accelerator_table_unittest.cc', 'accelerators/magnifier_key_scroller_unittest.cc', - 'accelerators/nested_dispatcher_controller_unittest.cc', 'accelerators/spoken_feedback_toggler_unittest.cc', 'autoclick/autoclick_unittest.cc', 'desktop_background/desktop_background_controller_unittest.cc', diff --git a/ash/shell.cc b/ash/shell.cc index c0a1765..1904f96 100644 --- a/ash/shell.cc +++ b/ash/shell.cc @@ -10,7 +10,7 @@ #include "ash/accelerators/accelerator_controller.h" #include "ash/accelerators/accelerator_filter.h" #include "ash/accelerators/focus_manager_factory.h" -#include "ash/accelerators/nested_dispatcher_controller.h" +#include "ash/accelerators/nested_accelerator_delegate.h" #include "ash/accelerometer/accelerometer_controller.h" #include "ash/ash_switches.h" #include "ash/autoclick/autoclick_controller.h" @@ -108,6 +108,7 @@ #include "ui/wm/core/compound_event_filter.h" #include "ui/wm/core/focus_controller.h" #include "ui/wm/core/input_method_event_filter.h" +#include "ui/wm/core/nested_accelerator_controller.h" #include "ui/wm/core/shadow_controller.h" #include "ui/wm/core/user_activity_detector.h" #include "ui/wm/core/visibility_controller.h" @@ -753,7 +754,7 @@ Shell::~Shell() { partial_magnification_controller_.reset(); tooltip_controller_.reset(); event_client_.reset(); - nested_dispatcher_controller_.reset(); + nested_accelerator_controller_.reset(); toplevel_window_event_handler_.reset(); visibility_controller_.reset(); // |shelf_item_delegate_manager_| observes |shelf_model_|. It must be @@ -879,7 +880,8 @@ void Shell::Init(const ShellInitParams& init_params) { cursor_manager_.SetDisplay(GetScreen()->GetPrimaryDisplay()); - nested_dispatcher_controller_.reset(new NestedDispatcherController); + nested_accelerator_controller_.reset( + new ::wm::NestedAcceleratorController(new NestedAcceleratorDelegate)); accelerator_controller_.reset(new AcceleratorController); maximize_mode_controller_.reset(new MaximizeModeController()); @@ -1092,9 +1094,9 @@ void Shell::InitRootWindow(aura::Window* root_window) { root_window->AddPreTargetHandler(toplevel_window_event_handler_.get()); root_window->AddPostTargetHandler(toplevel_window_event_handler_.get()); - if (nested_dispatcher_controller_) { + if (nested_accelerator_controller_) { aura::client::SetDispatcherClient(root_window, - nested_dispatcher_controller_.get()); + nested_accelerator_controller_.get()); } } diff --git a/ash/shell.h b/ash/shell.h index e889131..354d653 100644 --- a/ash/shell.h +++ b/ash/shell.h @@ -64,6 +64,7 @@ class TooltipController; namespace wm { class CompoundEventFilter; class InputMethodEventFilter; +class NestedAcceleratorController; class ShadowController; class VisibilityController; class UserActivityDetector; @@ -106,7 +107,6 @@ class MaximizeModeWindowManager; class MediaDelegate; class MouseCursorEventFilter; class MruWindowTracker; -class NestedDispatcherController; class NewWindowDelegate; class OverlayEventFilter; class PartialMagnificationController; @@ -623,7 +623,7 @@ class ASH_EXPORT Shell : public SystemModalContainerEventFilterDelegate, std::vector<WindowAndBoundsPair> to_restore_; scoped_ptr<UserMetricsRecorder> user_metrics_recorder_; - scoped_ptr<NestedDispatcherController> nested_dispatcher_controller_; + scoped_ptr< ::wm::NestedAcceleratorController> nested_accelerator_controller_; scoped_ptr<AcceleratorController> accelerator_controller_; scoped_ptr<ShellDelegate> delegate_; scoped_ptr<SystemTrayDelegate> system_tray_delegate_; diff --git a/ui/wm/core/DEPS b/ui/wm/core/DEPS index 54c7090..8540601 100644 --- a/ui/wm/core/DEPS +++ b/ui/wm/core/DEPS @@ -1,6 +1,7 @@ include_rules = [ "+grit/ui_resources.h", "+ui/aura", + "+ui/base/accelerators", "+ui/base/cursor", "+ui/base/hit_test.h", "+ui/base/ime", diff --git a/ash/accelerators/nested_dispatcher_controller.cc b/ui/wm/core/nested_accelerator_controller.cc index d963db0..782ac6d 100644 --- a/ash/accelerators/nested_dispatcher_controller.cc +++ b/ui/wm/core/nested_accelerator_controller.cc @@ -1,30 +1,34 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 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/accelerators/nested_dispatcher_controller.h" +#include "ui/wm/core/nested_accelerator_controller.h" -#include "ash/accelerators/accelerator_dispatcher.h" -#include "ash/shell.h" #include "base/auto_reset.h" #include "base/run_loop.h" +#include "ui/wm/core/nested_accelerator_delegate.h" +#include "ui/wm/core/nested_accelerator_dispatcher.h" -namespace ash { +namespace wm { -NestedDispatcherController::NestedDispatcherController() { +NestedAcceleratorController::NestedAcceleratorController( + NestedAcceleratorDelegate* delegate) + : dispatcher_delegate_(delegate) { + DCHECK(delegate); } -NestedDispatcherController::~NestedDispatcherController() { +NestedAcceleratorController::~NestedAcceleratorController() { } -void NestedDispatcherController::RunWithDispatcher( +void NestedAcceleratorController::RunWithDispatcher( base::MessagePumpDispatcher* nested_dispatcher) { base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); base::MessageLoopForUI::ScopedNestableTaskAllower allow_nested(loop); - scoped_ptr<AcceleratorDispatcher> old_accelerator_dispatcher = + scoped_ptr<NestedAcceleratorDispatcher> old_accelerator_dispatcher = accelerator_dispatcher_.Pass(); - accelerator_dispatcher_ = AcceleratorDispatcher::Create(nested_dispatcher); + accelerator_dispatcher_ = NestedAcceleratorDispatcher::Create( + dispatcher_delegate_.get(), nested_dispatcher); // TODO(jbates) crbug.com/134753 Find quitters of this RunLoop and have them // use run_loop.QuitClosure(). @@ -35,10 +39,10 @@ void NestedDispatcherController::RunWithDispatcher( accelerator_dispatcher_ = old_accelerator_dispatcher.Pass(); } -void NestedDispatcherController::QuitNestedMessageLoop() { +void NestedAcceleratorController::QuitNestedMessageLoop() { CHECK(!quit_closure_.is_null()); quit_closure_.Run(); accelerator_dispatcher_.reset(); } -} // namespace ash +} // namespace wm diff --git a/ash/accelerators/nested_dispatcher_controller.h b/ui/wm/core/nested_accelerator_controller.h index ebac2d2..2adfcbc 100644 --- a/ash/accelerators/nested_dispatcher_controller.h +++ b/ui/wm/core/nested_accelerator_controller.h @@ -1,28 +1,29 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 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_ACCELERATORS_NESTED_DISPATCHER_CONTROLLER_H_ -#define ASH_ACCELERATORS_NESTED_DISPATCHER_CONTROLLER_H_ +#ifndef UI_WM_CORE_NESTED_ACCELERATOR_CONTROLLER_H_ +#define UI_WM_CORE_NESTED_ACCELERATOR_CONTROLLER_H_ -#include "ash/ash_export.h" #include "base/callback.h" #include "base/message_loop/message_loop.h" #include "ui/wm/public/dispatcher_client.h" +#include "ui/wm/wm_export.h" -namespace ash { +namespace wm { -class AcceleratorDispatcher; +class NestedAcceleratorDelegate; +class NestedAcceleratorDispatcher; // Creates a dispatcher which wraps another dispatcher. // The outer dispatcher runs first and performs ash specific handling. // If it does not consume the event it forwards the event to the nested // dispatcher. -class ASH_EXPORT NestedDispatcherController +class WM_EXPORT NestedAcceleratorController : public aura::client::DispatcherClient { public: - NestedDispatcherController(); - virtual ~NestedDispatcherController(); + explicit NestedAcceleratorController(NestedAcceleratorDelegate* delegate); + virtual ~NestedAcceleratorController(); // aura::client::DispatcherClient: virtual void RunWithDispatcher( @@ -31,11 +32,12 @@ class ASH_EXPORT NestedDispatcherController private: base::Closure quit_closure_; - scoped_ptr<AcceleratorDispatcher> accelerator_dispatcher_; + scoped_ptr<NestedAcceleratorDispatcher> accelerator_dispatcher_; + scoped_ptr<NestedAcceleratorDelegate> dispatcher_delegate_; - DISALLOW_COPY_AND_ASSIGN(NestedDispatcherController); + DISALLOW_COPY_AND_ASSIGN(NestedAcceleratorController); }; -} // namespace ash +} // namespace wm -#endif // ASH_ACCELERATORS_NESTED_DISPATCHER_CONTROLLER_H_ +#endif // UI_WM_CORE_NESTED_ACCELERATOR_CONTROLLER_H_ diff --git a/ui/wm/core/nested_accelerator_controller_unittest.cc b/ui/wm/core/nested_accelerator_controller_unittest.cc new file mode 100644 index 0000000..b3bb3e8 --- /dev/null +++ b/ui/wm/core/nested_accelerator_controller_unittest.cc @@ -0,0 +1,201 @@ +// Copyright 2014 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 "ui/wm/core/nested_accelerator_controller.h" + +#include "base/bind.h" +#include "base/event_types.h" +#include "base/message_loop/message_loop.h" +#include "ui/aura/test/aura_test_base.h" +#include "ui/aura/test/test_windows.h" +#include "ui/aura/window.h" +#include "ui/aura/window_event_dispatcher.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/base/accelerators/accelerator_manager.h" +#include "ui/events/event_constants.h" +#include "ui/events/event_utils.h" +#include "ui/events/platform/platform_event_dispatcher.h" +#include "ui/events/platform/platform_event_source.h" +#include "ui/events/platform/scoped_event_dispatcher.h" +#include "ui/wm/core/nested_accelerator_delegate.h" +#include "ui/wm/public/dispatcher_client.h" + +#if defined(USE_X11) +#include <X11/Xlib.h> +#include "ui/events/test/events_test_utils_x11.h" +#endif // USE_X11 + +namespace wm { +namespace test { + +namespace { + +class MockDispatcher : public ui::PlatformEventDispatcher { + public: + MockDispatcher() : num_key_events_dispatched_(0) {} + + int num_key_events_dispatched() { return num_key_events_dispatched_; } + + private: + // ui::PlatformEventDispatcher: + virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE { + return true; + } + virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE { + if (ui::EventTypeFromNative(event) == ui::ET_KEY_RELEASED) + num_key_events_dispatched_++; + return ui::POST_DISPATCH_NONE; + } + + int num_key_events_dispatched_; + + DISALLOW_COPY_AND_ASSIGN(MockDispatcher); +}; + +class TestTarget : public ui::AcceleratorTarget { + public: + TestTarget() : accelerator_pressed_count_(0) {} + virtual ~TestTarget() {} + + int accelerator_pressed_count() const { return accelerator_pressed_count_; } + + // Overridden from ui::AcceleratorTarget: + virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE { + accelerator_pressed_count_++; + return true; + } + virtual bool CanHandleAccelerators() const OVERRIDE { return true; } + + private: + int accelerator_pressed_count_; + + DISALLOW_COPY_AND_ASSIGN(TestTarget); +}; + +void DispatchKeyReleaseA(aura::Window* root_window) { +// Sending both keydown and keyup is necessary here because the accelerator +// manager only checks a keyup event following a keydown event. See +// ShouldHandle() in ui/base/accelerators/accelerator_manager.cc for details. +#if defined(OS_WIN) + MSG native_event_down = {NULL, WM_KEYDOWN, ui::VKEY_A, 0}; + root_window->host()->PostNativeEvent(native_event_down); + MSG native_event_up = {NULL, WM_KEYUP, ui::VKEY_A, 0}; + root_window->host()->PostNativeEvent(native_event_up); +#elif defined(USE_X11) + ui::ScopedXI2Event native_event; + native_event.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, 0); + aura::WindowTreeHost* host = root_window->GetHost(); + host->PostNativeEvent(native_event); + native_event.InitKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_A, 0); + host->PostNativeEvent(native_event); +#endif + // Make sure the inner message-loop terminates after dispatching the events. + base::MessageLoop::current()->PostTask( + FROM_HERE, base::MessageLoop::current()->QuitClosure()); +} + +class MockNestedAcceleratorDelegate : public NestedAcceleratorDelegate { + public: + MockNestedAcceleratorDelegate() + : accelerator_manager_(new ui::AcceleratorManager) {} + virtual ~MockNestedAcceleratorDelegate() {} + + // NestedAcceleratorDelegate: + virtual bool ShouldProcessEventNow(const ui::KeyEvent& key_event) OVERRIDE { + return true; + } + virtual bool ProcessEvent(const ui::KeyEvent& key_event) OVERRIDE { + const int kModifierMask = + (ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN); + ui::Accelerator accelerator(key_event.key_code(), + key_event.flags() & kModifierMask); + if (key_event.type() == ui::ET_KEY_RELEASED) + accelerator.set_type(ui::ET_KEY_RELEASED); + return accelerator_manager_->Process(accelerator); + } + + void Register(const ui::Accelerator& accelerator, + ui::AcceleratorTarget* target) { + accelerator_manager_->Register( + accelerator, ui::AcceleratorManager::kNormalPriority, target); + } + + private: + scoped_ptr<ui::AcceleratorManager> accelerator_manager_; + + DISALLOW_COPY_AND_ASSIGN(MockNestedAcceleratorDelegate); +}; + +class NestedAcceleratorTest : public aura::test::AuraTestBase { + public: + NestedAcceleratorTest() {} + virtual ~NestedAcceleratorTest() {} + + virtual void SetUp() OVERRIDE { + AuraTestBase::SetUp(); + delegate_ = new MockNestedAcceleratorDelegate(); + nested_accelerator_controller_.reset( + new NestedAcceleratorController(delegate_)); + aura::client::SetDispatcherClient(root_window(), + nested_accelerator_controller_.get()); + } + + virtual void TearDown() OVERRIDE { + aura::client::SetDispatcherClient(root_window(), NULL); + AuraTestBase::TearDown(); + delegate_ = NULL; + nested_accelerator_controller_.reset(); + } + + MockNestedAcceleratorDelegate* delegate() { return delegate_; } + + private: + scoped_ptr<NestedAcceleratorController> nested_accelerator_controller_; + MockNestedAcceleratorDelegate* delegate_; + + DISALLOW_COPY_AND_ASSIGN(NestedAcceleratorTest); +}; + +} // namespace + +// Aura window above lock screen in z order. +TEST_F(NestedAcceleratorTest, AssociatedWindowAboveLockScreen) { + MockDispatcher inner_dispatcher; + scoped_ptr<aura::Window> mock_lock_container( + CreateNormalWindow(0, root_window(), NULL)); + aura::test::CreateTestWindowWithId(1, mock_lock_container.get()); + + scoped_ptr<aura::Window> associated_window( + CreateNormalWindow(2, root_window(), NULL)); + EXPECT_TRUE(aura::test::WindowIsAbove(associated_window.get(), + mock_lock_container.get())); + + DispatchKeyReleaseA(root_window()); + scoped_ptr<ui::ScopedEventDispatcher> override_dispatcher = + ui::PlatformEventSource::GetInstance()->OverrideDispatcher( + &inner_dispatcher); + aura::client::GetDispatcherClient(root_window())->RunWithDispatcher(NULL); + EXPECT_EQ(1, inner_dispatcher.num_key_events_dispatched()); +} + +// Test that the nested dispatcher handles accelerators. +TEST_F(NestedAcceleratorTest, AcceleratorsHandled) { + MockDispatcher inner_dispatcher; + ui::Accelerator accelerator(ui::VKEY_A, ui::EF_NONE); + accelerator.set_type(ui::ET_KEY_RELEASED); + TestTarget target; + delegate()->Register(accelerator, &target); + + DispatchKeyReleaseA(root_window()); + scoped_ptr<ui::ScopedEventDispatcher> override_dispatcher = + ui::PlatformEventSource::GetInstance()->OverrideDispatcher( + &inner_dispatcher); + aura::client::GetDispatcherClient(root_window())->RunWithDispatcher(NULL); + EXPECT_EQ(0, inner_dispatcher.num_key_events_dispatched()); + EXPECT_EQ(1, target.accelerator_pressed_count()); +} + +} // namespace test +} // namespace wm diff --git a/ui/wm/core/nested_accelerator_delegate.h b/ui/wm/core/nested_accelerator_delegate.h new file mode 100644 index 0000000..45b9e2a --- /dev/null +++ b/ui/wm/core/nested_accelerator_delegate.h @@ -0,0 +1,31 @@ +// Copyright 2014 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 UI_WM_CORE_NESTED_ACCELERATOR_DELEGATE_H_ +#define UI_WM_CORE_NESTED_ACCELERATOR_DELEGATE_H_ + +namespace ui { +class KeyEvent; +} + +namespace wm { + +// A delegate interface that implements the behavior of nested accelerator +// handling. +class NestedAcceleratorDelegate { + public: + virtual ~NestedAcceleratorDelegate() {} + + // If the key event should be ignored now and instead be reposted so that next + // event loop. + virtual bool ShouldProcessEventNow(const ui::KeyEvent& key_event) = 0; + + // Attempts to process an accelerator for the key-event. + // Returns whether an accelerator was triggered and processed. + virtual bool ProcessEvent(const ui::KeyEvent& key_event) = 0; +}; + +} // namespace wm + +#endif // UI_WM_CORE_NESTED_ACCELERATOR_DELEGATE_H_ diff --git a/ui/wm/core/nested_accelerator_dispatcher.cc b/ui/wm/core/nested_accelerator_dispatcher.cc new file mode 100644 index 0000000..d37c93c --- /dev/null +++ b/ui/wm/core/nested_accelerator_dispatcher.cc @@ -0,0 +1,21 @@ +// Copyright 2014 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 "ui/wm/core/nested_accelerator_dispatcher.h" + +#include "base/logging.h" +#include "ui/wm/core/nested_accelerator_delegate.h" + +namespace wm { + +NestedAcceleratorDispatcher::NestedAcceleratorDispatcher( + NestedAcceleratorDelegate* delegate) + : delegate_(delegate) { + DCHECK(delegate); +} + +NestedAcceleratorDispatcher::~NestedAcceleratorDispatcher() { +} + +} // namespace wm diff --git a/ui/wm/core/nested_accelerator_dispatcher.h b/ui/wm/core/nested_accelerator_dispatcher.h new file mode 100644 index 0000000..df5dd08 --- /dev/null +++ b/ui/wm/core/nested_accelerator_dispatcher.h @@ -0,0 +1,55 @@ +// Copyright 2014 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 UI_WM_CORE_NESTED_ACCELERATOR_DISPATCHER_H_ +#define UI_WM_CORE_NESTED_ACCELERATOR_DISPATCHER_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "ui/wm/wm_export.h" + +namespace base { +class MessagePumpDispatcher; +class RunLoop; +} + +namespace ui { +class KeyEvent; +} + +namespace wm { + +class NestedAcceleratorDelegate; + +// Dispatcher for handling accelerators from menu. +// +// Wraps a nested dispatcher to which control is passed if no accelerator key +// has been pressed. If the nested dispatcher is NULL, then the control is +// passed back to the default dispatcher. +// TODO(pkotwicz): Add support for a |nested_dispatcher| which sends +// events to a system IME. +class WM_EXPORT NestedAcceleratorDispatcher { + public: + virtual ~NestedAcceleratorDispatcher(); + + static scoped_ptr<NestedAcceleratorDispatcher> Create( + NestedAcceleratorDelegate* dispatcher_delegate, + base::MessagePumpDispatcher* nested_dispatcher); + + // Creates a base::RunLoop object to run a nested message loop. + virtual scoped_ptr<base::RunLoop> CreateRunLoop() = 0; + + protected: + explicit NestedAcceleratorDispatcher(NestedAcceleratorDelegate* delegate); + + NestedAcceleratorDelegate* + delegate_; // Owned by NestedAcceleratorController. + + private: + DISALLOW_COPY_AND_ASSIGN(NestedAcceleratorDispatcher); +}; + +} // namespace wm + +#endif // UI_WM_CORE_NESTED_ACCELERATOR_DISPATCHER_H_ diff --git a/ash/accelerators/accelerator_dispatcher_linux.cc b/ui/wm/core/nested_accelerator_dispatcher_linux.cc index b5494dd..bf21d3f 100644 --- a/ash/accelerators/accelerator_dispatcher_linux.cc +++ b/ui/wm/core/nested_accelerator_dispatcher_linux.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/accelerators/accelerator_dispatcher.h" +#include "ui/wm/core/nested_accelerator_dispatcher.h" #include "base/memory/scoped_ptr.h" #include "base/run_loop.h" @@ -10,12 +10,13 @@ #include "ui/events/platform/platform_event_dispatcher.h" #include "ui/events/platform/platform_event_source.h" #include "ui/events/platform/scoped_event_dispatcher.h" +#include "ui/wm/core/nested_accelerator_delegate.h" #if defined(USE_X11) #include <X11/Xlib.h> #endif -namespace ash { +namespace wm { namespace { @@ -41,13 +42,14 @@ scoped_ptr<ui::ScopedEventDispatcher> OverrideDispatcher( } // namespace -class AcceleratorDispatcherLinux : public AcceleratorDispatcher, - public ui::PlatformEventDispatcher { +class NestedAcceleratorDispatcherLinux : public NestedAcceleratorDispatcher, + public ui::PlatformEventDispatcher { public: - AcceleratorDispatcherLinux() - : restore_dispatcher_(OverrideDispatcher(this)) {} + explicit NestedAcceleratorDispatcherLinux(NestedAcceleratorDelegate* delegate) + : NestedAcceleratorDispatcher(delegate), + restore_dispatcher_(OverrideDispatcher(this)) {} - virtual ~AcceleratorDispatcherLinux() {} + virtual ~NestedAcceleratorDispatcherLinux() {} private: // AcceleratorDispatcher: @@ -63,7 +65,7 @@ class AcceleratorDispatcherLinux : public AcceleratorDispatcher, virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE { if (IsKeyEvent(event)) { ui::KeyEvent key_event(event, false); - if (MenuClosedForPossibleAccelerator(key_event)) { + if (!delegate_->ShouldProcessEventNow(key_event)) { #if defined(USE_X11) XPutBackEvent(event->xany.display, event); #else @@ -72,23 +74,25 @@ class AcceleratorDispatcherLinux : public AcceleratorDispatcher, return ui::POST_DISPATCH_NONE; } - if (AcceleratorProcessedForKeyEvent(key_event)) + if (delegate_->ProcessEvent(key_event)) return ui::POST_DISPATCH_NONE; } - ui::PlatformEventDispatcher* prev = *restore_dispatcher_; + return prev ? prev->DispatchEvent(event) : ui::POST_DISPATCH_PERFORM_DEFAULT; } scoped_ptr<ui::ScopedEventDispatcher> restore_dispatcher_; - DISALLOW_COPY_AND_ASSIGN(AcceleratorDispatcherLinux); + DISALLOW_COPY_AND_ASSIGN(NestedAcceleratorDispatcherLinux); }; -scoped_ptr<AcceleratorDispatcher> AcceleratorDispatcher::Create( +scoped_ptr<NestedAcceleratorDispatcher> NestedAcceleratorDispatcher::Create( + NestedAcceleratorDelegate* delegate, base::MessagePumpDispatcher* nested_dispatcher) { - return scoped_ptr<AcceleratorDispatcher>(new AcceleratorDispatcherLinux()); + return scoped_ptr<NestedAcceleratorDispatcher>( + new NestedAcceleratorDispatcherLinux(delegate)); } -} // namespace ash +} // namespace wm diff --git a/ash/accelerators/accelerator_dispatcher_win.cc b/ui/wm/core/nested_accelerator_dispatcher_win.cc index 35005f3..a6a5bd9 100644 --- a/ash/accelerators/accelerator_dispatcher_win.cc +++ b/ui/wm/core/nested_accelerator_dispatcher_win.cc @@ -2,16 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/accelerators/accelerator_dispatcher.h" +#include "ui/wm/core/nested_accelerator_dispatcher.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_pump_dispatcher.h" #include "base/run_loop.h" #include "ui/events/event.h" +#include "ui/wm/core/nested_accelerator_delegate.h" using base::MessagePumpDispatcher; -namespace ash { +namespace wm { namespace { @@ -22,15 +23,16 @@ bool IsKeyEvent(const MSG& msg) { } // namespace -class AcceleratorDispatcherWin : public AcceleratorDispatcher, - public MessagePumpDispatcher { +class NestedAcceleratorDispatcherWin : public NestedAcceleratorDispatcher, + public MessagePumpDispatcher { public: - explicit AcceleratorDispatcherWin(MessagePumpDispatcher* nested) - : nested_dispatcher_(nested) {} - virtual ~AcceleratorDispatcherWin() {} + NestedAcceleratorDispatcherWin(NestedAcceleratorDelegate* delegate, + MessagePumpDispatcher* nested) + : NestedAcceleratorDispatcher(delegate), nested_dispatcher_(nested) {} + virtual ~NestedAcceleratorDispatcherWin() {} private: - // AcceleratorDispatcher: + // NestedAcceleratorDispatcher: virtual scoped_ptr<base::RunLoop> CreateRunLoop() OVERRIDE { return scoped_ptr<base::RunLoop>(new base::RunLoop(this)); } @@ -39,10 +41,10 @@ class AcceleratorDispatcherWin : public AcceleratorDispatcher, virtual uint32_t Dispatch(const MSG& event) OVERRIDE { if (IsKeyEvent(event)) { ui::KeyEvent key_event(event, false); - if (MenuClosedForPossibleAccelerator(key_event)) + if (!delegate_->ShouldProcessEventNow(key_event)) return POST_DISPATCH_QUIT_LOOP; - if (AcceleratorProcessedForKeyEvent(key_event)) + if (delegate_->ProcessEvent(key_event)) return POST_DISPATCH_NONE; } @@ -52,13 +54,14 @@ class AcceleratorDispatcherWin : public AcceleratorDispatcher, MessagePumpDispatcher* nested_dispatcher_; - DISALLOW_COPY_AND_ASSIGN(AcceleratorDispatcherWin); + DISALLOW_COPY_AND_ASSIGN(NestedAcceleratorDispatcherWin); }; -scoped_ptr<AcceleratorDispatcher> AcceleratorDispatcher::Create( +scoped_ptr<NestedAcceleratorDispatcher> NestedAcceleratorDispatcher::Create( + NestedAcceleratorDelegate* delegate, MessagePumpDispatcher* nested_dispatcher) { - return scoped_ptr<AcceleratorDispatcher>( - new AcceleratorDispatcherWin(nested_dispatcher)); + return scoped_ptr<NestedAcceleratorDispatcher>( + new NestedAcceleratorDispatcherWin(delegate, nested_dispatcher)); } -} // namespace ash +} // namespace wm diff --git a/ui/wm/wm.gyp b/ui/wm/wm.gyp index 537f67a..1a86102 100644 --- a/ui/wm/wm.gyp +++ b/ui/wm/wm.gyp @@ -26,6 +26,14 @@ 'WM_IMPLEMENTATION', ], 'sources': [ + 'core/nested_accelerator_dispatcher_linux.cc', + 'core/nested_accelerator_dispatcher_win.cc', + 'core/nested_accelerator_dispatcher.cc', + 'core/nested_accelerator_dispatcher.h', + 'core/nested_accelerator_delegate.h', + 'core/nested_accelerator_controller.cc', + 'core/nested_accelerator_controller.h', + 'core/base_focus_rules.h', 'core/base_focus_rules.cc', 'core/base_focus_rules.h', 'core/capture_controller.cc', @@ -121,6 +129,7 @@ 'core/focus_controller_unittest.cc', 'core/input_method_event_filter_unittest.cc', 'core/image_grid_unittest.cc', + 'core/nested_accelerator_controller_unittest.cc', 'core/shadow_controller_unittest.cc', 'core/transient_window_manager_unittest.cc', 'core/transient_window_stacking_client_unittest.cc', |