diff options
-rw-r--r-- | ash/wm/ash_native_cursor_manager.cc | 6 | ||||
-rw-r--r-- | ash/wm/window_manager_unittest.cc | 84 | ||||
-rw-r--r-- | content/browser/renderer_host/render_widget_host_impl.cc | 4 | ||||
-rw-r--r-- | content/browser/renderer_host/render_widget_host_impl.h | 3 | ||||
-rw-r--r-- | content/browser/renderer_host/render_widget_host_view_aura.cc | 37 | ||||
-rw-r--r-- | content/browser/renderer_host/render_widget_host_view_aura.h | 18 | ||||
-rw-r--r-- | content/common/input_messages.h | 4 | ||||
-rw-r--r-- | content/renderer/render_widget.cc | 7 | ||||
-rw-r--r-- | content/renderer/render_widget.h | 1 | ||||
-rw-r--r-- | ui/aura/aura.gyp | 1 | ||||
-rw-r--r-- | ui/aura/client/cursor_client.h | 5 | ||||
-rw-r--r-- | ui/aura/client/cursor_client_observer.h | 24 | ||||
-rw-r--r-- | ui/views/corewm/compound_event_filter_unittest.cc | 8 | ||||
-rw-r--r-- | ui/views/corewm/cursor_manager.cc | 17 | ||||
-rw-r--r-- | ui/views/corewm/cursor_manager.h | 7 | ||||
-rw-r--r-- | ui/views/corewm/cursor_manager_unittest.cc | 76 |
16 files changed, 296 insertions, 6 deletions
diff --git a/ash/wm/ash_native_cursor_manager.cc b/ash/wm/ash_native_cursor_manager.cc index be9c6b7..dd72af1 100644 --- a/ash/wm/ash_native_cursor_manager.cc +++ b/ash/wm/ash_native_cursor_manager.cc @@ -13,10 +13,6 @@ namespace { -// The coordinate of the cursor used when the mouse events are disabled. -const int kDisabledCursorLocationX = -10000; -const int kDisabledCursorLocationY = -10000; - void SetCursorOnAllRootWindows(gfx::NativeCursor cursor) { ash::Shell::RootWindowList root_windows = ash::Shell::GetInstance()->GetAllRootWindows(); @@ -99,8 +95,6 @@ void AshNativeCursorManager::SetMouseEventsEnabled( disabled_cursor_location_); } else { disabled_cursor_location_ = aura::Env::GetInstance()->last_mouse_location(); - aura::Env::GetInstance()->set_last_mouse_location( - gfx::Point(kDisabledCursorLocationX, kDisabledCursorLocationY)); } SetVisibility(delegate->GetCurrentVisibility(), delegate); diff --git a/ash/wm/window_manager_unittest.cc b/ash/wm/window_manager_unittest.cc index e12c9db..936b29a 100644 --- a/ash/wm/window_manager_unittest.cc +++ b/ash/wm/window_manager_unittest.cc @@ -11,6 +11,7 @@ #include "ash/wm/window_util.h" #include "ui/aura/client/activation_client.h" #include "ui/aura/client/activation_delegate.h" +#include "ui/aura/client/cursor_client_observer.h" #include "ui/aura/client/focus_client.h" #include "ui/aura/env.h" #include "ui/aura/root_window.h" @@ -30,6 +31,28 @@ namespace { +class TestingCursorClientObserver : public aura::client::CursorClientObserver { + public: + TestingCursorClientObserver() + : cursor_visibility_(false), + did_visibility_change_(false) {} + void reset() { cursor_visibility_ = did_visibility_change_ = false; } + bool is_cursor_visible() const { return cursor_visibility_; } + bool did_visibility_change() const { return did_visibility_change_; } + + // Overridden from aura::client::CursorClientObserver: + virtual void OnCursorVisibilityChanged(bool is_visible) OVERRIDE { + cursor_visibility_ = is_visible; + did_visibility_change_ = true; + } + + private: + bool cursor_visibility_; + bool did_visibility_change_; + + DISALLOW_COPY_AND_ASSIGN(TestingCursorClientObserver); +}; + base::TimeDelta getTime() { return ui::EventTimeForNow(); } @@ -753,4 +776,65 @@ TEST_F(WindowManagerTest, UpdateCursorVisibilityOnKeyEvent) { EXPECT_TRUE(cursor_manager->IsMouseEventsEnabled()); } +TEST_F(WindowManagerTest, TestCursorClientObserver) { + aura::test::EventGenerator& generator = GetEventGenerator(); + views::corewm::CursorManager* cursor_manager = + ash::Shell::GetInstance()->cursor_manager(); + + scoped_ptr<aura::Window> w1(CreateTestWindowInShell( + SK_ColorWHITE, -1, gfx::Rect(0, 0, 100, 100))); + wm::ActivateWindow(w1.get()); + + // Add two observers. Both should have OnCursorVisibilityChanged() + // invoked when an event changes the visibility of the cursor. + TestingCursorClientObserver observer_a; + TestingCursorClientObserver observer_b; + cursor_manager->AddObserver(&observer_a); + cursor_manager->AddObserver(&observer_b); + + // Initial state before any events have been sent. + observer_a.reset(); + observer_b.reset(); + EXPECT_FALSE(observer_a.did_visibility_change()); + EXPECT_FALSE(observer_b.did_visibility_change()); + EXPECT_FALSE(observer_a.is_cursor_visible()); + EXPECT_FALSE(observer_b.is_cursor_visible()); + + // Keypress should hide the cursor. + generator.PressKey(ui::VKEY_A, ui::EF_NONE); + EXPECT_TRUE(observer_a.did_visibility_change()); + EXPECT_TRUE(observer_b.did_visibility_change()); + EXPECT_FALSE(observer_a.is_cursor_visible()); + EXPECT_FALSE(observer_b.is_cursor_visible()); + + // Mouse move should show the cursor. + observer_a.reset(); + observer_b.reset(); + generator.MoveMouseTo(50, 50); + EXPECT_TRUE(observer_a.did_visibility_change()); + EXPECT_TRUE(observer_b.did_visibility_change()); + EXPECT_TRUE(observer_a.is_cursor_visible()); + EXPECT_TRUE(observer_b.is_cursor_visible()); + + // Remove observer_b. Its OnCursorVisibilityChanged() should + // not be invoked past this point. + cursor_manager->RemoveObserver(&observer_b); + + // Gesture tap should hide the cursor. + observer_a.reset(); + observer_b.reset(); + generator.GestureTapAt(gfx::Point(25, 25)); + EXPECT_TRUE(observer_a.did_visibility_change()); + EXPECT_FALSE(observer_b.did_visibility_change()); + EXPECT_FALSE(observer_a.is_cursor_visible()); + + // Mouse move should show the cursor. + observer_a.reset(); + observer_b.reset(); + generator.MoveMouseTo(50, 50); + EXPECT_TRUE(observer_a.did_visibility_change()); + EXPECT_FALSE(observer_b.did_visibility_change()); + EXPECT_TRUE(observer_a.is_cursor_visible()); +} + } // namespace ash diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index f2d095f..d0a2d5c 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc @@ -1143,6 +1143,10 @@ void RenderWidgetHostImpl::ForwardKeyboardEvent( } } +void RenderWidgetHostImpl::SendCursorVisibilityState(bool is_visible) { + Send(new InputMsg_CursorVisibilityChange(GetRoutingID(), is_visible)); +} + void RenderWidgetHostImpl::SendInputEvent(const WebInputEvent& input_event, int event_size, bool is_keyboard_shortcut) { diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index b8ad8bc..487a9e9 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h @@ -199,6 +199,9 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, // Called to notify the RenderWidget that it has lost the mouse lock. virtual void LostMouseLock(); + // Noifies the RenderWidget of the current mouse cursor visibility state. + void SendCursorVisibilityState(bool is_visible); + // Tells us whether the page is rendered directly via the GPU process. bool is_accelerated_compositing_active() { return is_accelerated_compositing_active_; diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index 17c11a1..c28c9ee 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc @@ -41,6 +41,7 @@ #include "ui/aura/client/activation_client.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/cursor_client.h" +#include "ui/aura/client/cursor_client_observer.h" #include "ui/aura/client/focus_client.h" #include "ui/aura/client/screen_position_client.h" #include "ui/aura/client/stacking_client.h" @@ -634,6 +635,7 @@ RenderWidgetHostViewAura::RenderWidgetHostViewAura(RenderWidgetHost* host) synthetic_move_sent_(false), accelerated_compositing_state_changed_(false), can_lock_compositor_(YES), + cursor_visibility_state_in_renderer_(UNKNOWN), paint_observer_(NULL), touch_editing_client_(NULL) { host_->SetView(this); @@ -730,6 +732,11 @@ void RenderWidgetHostViewAura::WasShown() { return; host_->WasShown(); + aura::client::CursorClient* cursor_client = + aura::client::GetCursorClient(window_->GetRootWindow()); + if (cursor_client) + NotifyRendererOfCursorVisibilityState(cursor_client->IsCursorVisible()); + if (!current_surface_ && host_->is_accelerated_compositing_active() && !released_front_lock_.get()) { released_front_lock_ = GetCompositor()->GetCompositorLock(); @@ -2515,6 +2522,13 @@ void RenderWidgetHostViewAura::OnWindowActivated(aura::Window* gained_active, } //////////////////////////////////////////////////////////////////////////////// +// RenderWidgetHostViewAura, aura::client::CursorClientObserver implementation: + +void RenderWidgetHostViewAura::OnCursorVisibilityChanged(bool is_visible) { + NotifyRendererOfCursorVisibilityState(is_visible); +} + +//////////////////////////////////////////////////////////////////////////////// // RenderWidgetHostViewAura, aura::client::FocusChangeObserver implementation: void RenderWidgetHostViewAura::OnWindowFocused(aura::Window* gained_focus, @@ -2827,6 +2841,17 @@ void RenderWidgetHostViewAura::ModifyEventMovementAndCoords( } } +void RenderWidgetHostViewAura::NotifyRendererOfCursorVisibilityState( + bool is_visible) { + if (host_->is_hidden() || + (cursor_visibility_state_in_renderer_ == VISIBLE && is_visible) || + (cursor_visibility_state_in_renderer_ == NOT_VISIBLE && !is_visible)) + return; + + cursor_visibility_state_in_renderer_ = is_visible ? VISIBLE : NOT_VISIBLE; + host_->SendCursorVisibilityState(is_visible); +} + void RenderWidgetHostViewAura::SchedulePaintIfNotInClip( const gfx::Rect& rect, const gfx::Rect& clip) { @@ -2877,9 +2902,21 @@ void RenderWidgetHostViewAura::AddedToRootWindow() { UpdateScreenInfo(window_); if (popup_type_ != WebKit::WebPopupTypeNone) event_filter_for_popup_exit_.reset(new EventFilterForPopupExit(this)); + + aura::client::CursorClient* cursor_client = + aura::client::GetCursorClient(window_->GetRootWindow()); + if (cursor_client) { + cursor_client->AddObserver(this); + NotifyRendererOfCursorVisibilityState(cursor_client->IsCursorVisible()); + } } void RenderWidgetHostViewAura::RemovingFromRootWindow() { + aura::client::CursorClient* cursor_client = + aura::client::GetCursorClient(window_->GetRootWindow()); + if (cursor_client) + cursor_client->RemoveObserver(this); + event_filter_for_popup_exit_.reset(); window_->GetRootWindow()->RemoveRootWindowObserver(this); host_->ParentChanged(0); diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index 86d6144..b1e3a7e 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h @@ -22,6 +22,7 @@ #include "third_party/skia/include/core/SkRegion.h" #include "ui/aura/client/activation_change_observer.h" #include "ui/aura/client/activation_delegate.h" +#include "ui/aura/client/cursor_client_observer.h" #include "ui/aura/client/focus_change_observer.h" #include "ui/aura/root_window_observer.h" #include "ui/aura/window_delegate.h" @@ -66,6 +67,7 @@ class RenderWidgetHostViewAura public aura::client::ActivationDelegate, public aura::client::ActivationChangeObserver, public aura::client::FocusChangeObserver, + public aura::client::CursorClientObserver, public ImageTransportFactoryObserver, public BrowserAccessibilityDelegate, public base::SupportsWeakPtr<RenderWidgetHostViewAura> { @@ -297,6 +299,9 @@ class RenderWidgetHostViewAura virtual void OnWindowActivated(aura::Window* gained_activation, aura::Window* lost_activation) OVERRIDE; + // Overridden from aura::client::CursorClientObserver: + virtual void OnCursorVisibilityChanged(bool is_visible) OVERRIDE; + // Overridden from aura::client::FocusChangeObserver: virtual void OnWindowFocused(aura::Window* gained_focus, aura::Window* lost_focus) OVERRIDE; @@ -386,6 +391,10 @@ class RenderWidgetHostViewAura // mouse lock on all mouse move events. void ModifyEventMovementAndCoords(WebKit::WebMouseEvent* event); + // Sends an IPC to the renderer process to communicate whether or not + // the mouse cursor is visible anywhere on the screen. + void NotifyRendererOfCursorVisibilityState(bool is_visible); + // If |clip| is non-empty and and doesn't contain |rect| or |clip| is empty // SchedulePaint() is invoked for |rect|. void SchedulePaintIfNotInClip(const gfx::Rect& rect, const gfx::Rect& clip); @@ -613,6 +622,15 @@ class RenderWidgetHostViewAura }; CanLockCompositorState can_lock_compositor_; + // Used to track the last cursor visibility update that was sent to the + // renderer via NotifyRendererOfCursorVisibilityState(). + enum CursorVisibilityState { + UNKNOWN, + VISIBLE, + NOT_VISIBLE, + }; + CursorVisibilityState cursor_visibility_state_in_renderer_; + // An observer to notify that the paint content of the view has changed. The // observer is not owned by the view, and must remove itself as an oberver // when it is being destroyed. diff --git a/content/common/input_messages.h b/content/common/input_messages.h index 1c459b4..2c9c0b9 100644 --- a/content/common/input_messages.h +++ b/content/common/input_messages.h @@ -38,6 +38,10 @@ IPC_MESSAGE_ROUTED2(InputMsg_HandleInputEvent, IPC::WebInputEventPointer /* event */, bool /* is_keyboard_shortcut */) +// Sends the cursor visibility state to the render widget. +IPC_MESSAGE_ROUTED1(InputMsg_CursorVisibilityChange, + bool /* is_visible */) + // This message notifies the renderer that the next key event is bound to one // or more pre-defined edit commands. If the next key event is not handled // by webkit, the specified edit commands shall be executed against current diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index 601c0dd..a9069aa 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc @@ -309,6 +309,8 @@ bool RenderWidget::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(RenderWidget, message) IPC_MESSAGE_HANDLER(InputMsg_HandleInputEvent, OnHandleInputEvent) + IPC_MESSAGE_HANDLER(InputMsg_CursorVisibilityChange, + OnCursorVisibilityChange) IPC_MESSAGE_HANDLER(InputMsg_MouseCaptureLost, OnMouseCaptureLost) IPC_MESSAGE_HANDLER(InputMsg_SetFocus, OnSetFocus) IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose) @@ -821,6 +823,11 @@ void RenderWidget::OnHandleInputEvent(const WebKit::WebInputEvent* input_event, } } +void RenderWidget::OnCursorVisibilityChange(bool is_visible) { + if (webwidget_) + webwidget_->setCursorVisibilityState(is_visible); +} + void RenderWidget::OnMouseCaptureLost() { if (webwidget_) webwidget_->mouseCaptureLost(); diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h index 3d17891..cf9f8fa 100644 --- a/content/renderer/render_widget.h +++ b/content/renderer/render_widget.h @@ -282,6 +282,7 @@ class CONTENT_EXPORT RenderWidget // RenderWidget IPC message handlers void OnHandleInputEvent(const WebKit::WebInputEvent* event, bool keyboard_shortcut); + void OnCursorVisibilityChange(bool is_visible); void OnMouseCaptureLost(); virtual void OnSetFocus(bool enable); void OnClose(); diff --git a/ui/aura/aura.gyp b/ui/aura/aura.gyp index f6ec2ce..3fd58f4 100644 --- a/ui/aura/aura.gyp +++ b/ui/aura/aura.gyp @@ -38,6 +38,7 @@ 'client/capture_delegate.h', 'client/cursor_client.cc', 'client/cursor_client.h', + 'client/cursor_client_observer.h', 'client/default_capture_client.cc', 'client/default_capture_client.h', 'client/dispatcher_client.cc', diff --git a/ui/aura/client/cursor_client.h b/ui/aura/client/cursor_client.h index fb2dde2..d79bed5 100644 --- a/ui/aura/client/cursor_client.h +++ b/ui/aura/client/cursor_client.h @@ -16,6 +16,7 @@ class Display; namespace aura { class Window; namespace client { +class CursorClientObserver; // An interface that receives cursor change events. class AURA_EXPORT CursorClient { @@ -60,6 +61,10 @@ class AURA_EXPORT CursorClient { // typically used to load non system cursors. virtual void SetCursorResourceModule(const string16& module_name) = 0; + // Used to add or remove a CursorClientObserver. + virtual void AddObserver(CursorClientObserver* observer) = 0; + virtual void RemoveObserver(CursorClientObserver* observer) = 0; + protected: virtual ~CursorClient() {} }; diff --git a/ui/aura/client/cursor_client_observer.h b/ui/aura/client/cursor_client_observer.h new file mode 100644 index 0000000..1a6d1a8 --- /dev/null +++ b/ui/aura/client/cursor_client_observer.h @@ -0,0 +1,24 @@ +// Copyright (c) 2013 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_AURA_CLIENT_CURSOR_CLIENT_OBSERVER_H_ +#define UI_AURA_CLIENT_CURSOR_CLIENT_OBSERVER_H_ + +#include "ui/aura/aura_export.h" + +namespace aura { +namespace client { + +class AURA_EXPORT CursorClientObserver { + public: + virtual void OnCursorVisibilityChanged(bool is_visible) = 0; + + protected: + virtual ~CursorClientObserver() {} +}; + +} // namespace client +} // namespace aura + +#endif // UI_AURA_CLIENT_CURSOR_CLIENT_OBSERVER_H_ diff --git a/ui/views/corewm/compound_event_filter_unittest.cc b/ui/views/corewm/compound_event_filter_unittest.cc index d3c32ee..412852c 100644 --- a/ui/views/corewm/compound_event_filter_unittest.cc +++ b/ui/views/corewm/compound_event_filter_unittest.cc @@ -65,6 +65,14 @@ class TestCursorClient : public aura::client::CursorClient { virtual void SetCursorResourceModule(const string16& module_name) OVERRIDE { } + virtual void AddObserver( + aura::client::CursorClientObserver* observer) OVERRIDE { + } + + virtual void RemoveObserver( + aura::client::CursorClientObserver* observer) OVERRIDE { + } + private: bool visible_; bool mouse_events_enabled_; diff --git a/ui/views/corewm/cursor_manager.cc b/ui/views/corewm/cursor_manager.cc index 24abfe2..9e7a3bd 100644 --- a/ui/views/corewm/cursor_manager.cc +++ b/ui/views/corewm/cursor_manager.cc @@ -5,6 +5,7 @@ #include "ui/views/corewm/cursor_manager.h" #include "base/logging.h" +#include "ui/aura/client/cursor_client_observer.h" #include "ui/views/corewm/native_cursor_manager.h" #include "ui/views/corewm/native_cursor_manager_delegate.h" @@ -86,6 +87,8 @@ void CursorManager::ShowCursor() { if (cursor_lock_count_ == 0 && IsCursorVisible() != state_on_unlock_->visible()) { delegate_->SetVisibility(state_on_unlock_->visible(), this); + FOR_EACH_OBSERVER(aura::client::CursorClientObserver, observers_, + OnCursorVisibilityChanged(true)); } } @@ -94,6 +97,8 @@ void CursorManager::HideCursor() { if (cursor_lock_count_ == 0 && IsCursorVisible() != state_on_unlock_->visible()) { delegate_->SetVisibility(state_on_unlock_->visible(), this); + FOR_EACH_OBSERVER(aura::client::CursorClientObserver, observers_, + OnCursorVisibilityChanged(false)); } } @@ -154,6 +159,16 @@ void CursorManager::SetCursorResourceModule(const string16& module_name) { delegate_->SetCursorResourceModule(module_name); } +void CursorManager::AddObserver( + aura::client::CursorClientObserver* observer) { + observers_.AddObserver(observer); +} + +void CursorManager::RemoveObserver( + aura::client::CursorClientObserver* observer) { + observers_.RemoveObserver(observer); +} + gfx::NativeCursor CursorManager::GetCurrentCursor() const { return current_state_->cursor(); } @@ -171,6 +186,8 @@ void CursorManager::CommitCursor(gfx::NativeCursor cursor) { } void CursorManager::CommitVisibility(bool visible) { + FOR_EACH_OBSERVER(aura::client::CursorClientObserver, observers_, + OnCursorVisibilityChanged(visible)); current_state_->SetVisible(visible); } diff --git a/ui/views/corewm/cursor_manager.h b/ui/views/corewm/cursor_manager.h index 7197995..136e4bd 100644 --- a/ui/views/corewm/cursor_manager.h +++ b/ui/views/corewm/cursor_manager.h @@ -8,6 +8,7 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" +#include "base/observer_list.h" #include "ui/aura/client/cursor_client.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/point.h" @@ -51,6 +52,10 @@ class VIEWS_EXPORT CursorManager : public aura::client::CursorClient, virtual void LockCursor() OVERRIDE; virtual void UnlockCursor() OVERRIDE; virtual void SetCursorResourceModule(const string16& module_name) OVERRIDE; + virtual void AddObserver( + aura::client::CursorClientObserver* observer) OVERRIDE; + virtual void RemoveObserver( + aura::client::CursorClientObserver* observer) OVERRIDE; private: // Overridden from NativeCursorManagerDelegate: @@ -73,6 +78,8 @@ class VIEWS_EXPORT CursorManager : public aura::client::CursorClient, // The cursor state to restore when the cursor is unlocked. scoped_ptr<internal::CursorState> state_on_unlock_; + ObserverList<aura::client::CursorClientObserver> observers_; + DISALLOW_COPY_AND_ASSIGN(CursorManager); }; diff --git a/ui/views/corewm/cursor_manager_unittest.cc b/ui/views/corewm/cursor_manager_unittest.cc index 3f53370..d05990f 100644 --- a/ui/views/corewm/cursor_manager_unittest.cc +++ b/ui/views/corewm/cursor_manager_unittest.cc @@ -4,6 +4,7 @@ #include "ui/views/corewm/cursor_manager.h" +#include "ui/aura/client/cursor_client_observer.h" #include "ui/views/corewm/native_cursor_manager.h" #include "ui/views/test/views_test_base.h" @@ -60,6 +61,28 @@ class CursorManagerTest : public views::ViewsTestBase { views::corewm::CursorManager cursor_manager_; }; +class TestingCursorClientObserver : public aura::client::CursorClientObserver { + public: + TestingCursorClientObserver() + : cursor_visibility_(false), + did_visibility_change_(false) {} + void reset() { cursor_visibility_ = did_visibility_change_ = false; } + bool is_cursor_visible() const { return cursor_visibility_; } + bool did_visibility_change() const { return did_visibility_change_; } + + // Overridden from aura::client::CursorClientObserver: + virtual void OnCursorVisibilityChanged(bool is_visible) OVERRIDE { + cursor_visibility_ = is_visible; + did_visibility_change_ = true; + } + + private: + bool cursor_visibility_; + bool did_visibility_change_; + + DISALLOW_COPY_AND_ASSIGN(TestingCursorClientObserver); +}; + TEST_F(CursorManagerTest, ShowHideCursor) { cursor_manager_.SetCursor(ui::kCursorCopy); EXPECT_EQ(ui::kCursorCopy, current_cursor().native_type()); @@ -244,3 +267,56 @@ TEST_F(CursorManagerTest, MultipleEnableMouseEvents) { cursor_manager_.UnlockCursor(); EXPECT_TRUE(cursor_manager_.IsCursorVisible()); } + +TEST_F(CursorManagerTest, TestCursorClientObserver) { + // Add two observers. Both should have OnCursorVisibilityChanged() + // invoked when the visibility of the cursor changes. + TestingCursorClientObserver observer_a; + TestingCursorClientObserver observer_b; + cursor_manager_.AddObserver(&observer_a); + cursor_manager_.AddObserver(&observer_b); + + // Initial state before any events have been sent. + observer_a.reset(); + observer_b.reset(); + EXPECT_FALSE(observer_a.did_visibility_change()); + EXPECT_FALSE(observer_b.did_visibility_change()); + EXPECT_FALSE(observer_a.is_cursor_visible()); + EXPECT_FALSE(observer_b.is_cursor_visible()); + + // Hide the cursor using HideCursor(). + cursor_manager_.HideCursor(); + EXPECT_TRUE(observer_a.did_visibility_change()); + EXPECT_TRUE(observer_b.did_visibility_change()); + EXPECT_FALSE(observer_a.is_cursor_visible()); + EXPECT_FALSE(observer_b.is_cursor_visible()); + + // Show the cursor using ShowCursor(). + observer_a.reset(); + observer_b.reset(); + cursor_manager_.ShowCursor(); + EXPECT_TRUE(observer_a.did_visibility_change()); + EXPECT_TRUE(observer_b.did_visibility_change()); + EXPECT_TRUE(observer_a.is_cursor_visible()); + EXPECT_TRUE(observer_b.is_cursor_visible()); + + // Remove observer_b. Its OnCursorVisibilityChanged() should + // not be invoked past this point. + cursor_manager_.RemoveObserver(&observer_b); + + // Hide the cursor using HideCursor(). + observer_a.reset(); + observer_b.reset(); + cursor_manager_.HideCursor(); + EXPECT_TRUE(observer_a.did_visibility_change()); + EXPECT_FALSE(observer_b.did_visibility_change()); + EXPECT_FALSE(observer_a.is_cursor_visible()); + + // Show the cursor using ShowCursor(). + observer_a.reset(); + observer_b.reset(); + cursor_manager_.ShowCursor(); + EXPECT_TRUE(observer_a.did_visibility_change()); + EXPECT_FALSE(observer_b.did_visibility_change()); + EXPECT_TRUE(observer_a.is_cursor_visible()); +} |