summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ash/wm/ash_native_cursor_manager.cc6
-rw-r--r--ash/wm/window_manager_unittest.cc84
-rw-r--r--content/browser/renderer_host/render_widget_host_impl.cc4
-rw-r--r--content/browser/renderer_host/render_widget_host_impl.h3
-rw-r--r--content/browser/renderer_host/render_widget_host_view_aura.cc37
-rw-r--r--content/browser/renderer_host/render_widget_host_view_aura.h18
-rw-r--r--content/common/input_messages.h4
-rw-r--r--content/renderer/render_widget.cc7
-rw-r--r--content/renderer/render_widget.h1
-rw-r--r--ui/aura/aura.gyp1
-rw-r--r--ui/aura/client/cursor_client.h5
-rw-r--r--ui/aura/client/cursor_client_observer.h24
-rw-r--r--ui/views/corewm/compound_event_filter_unittest.cc8
-rw-r--r--ui/views/corewm/cursor_manager.cc17
-rw-r--r--ui/views/corewm/cursor_manager.h7
-rw-r--r--ui/views/corewm/cursor_manager_unittest.cc76
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());
+}