summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ash/ash.gyp2
-rw-r--r--ash/display/mouse_cursor_event_filter.cc2
-rw-r--r--ash/drag_drop/drag_drop_controller.cc8
-rw-r--r--ash/drag_drop/drag_drop_controller.h2
-rw-r--r--ash/extended_desktop_unittest.cc6
-rw-r--r--ash/shell.cc3
-rw-r--r--ash/wm/cursor_manager.cc24
-rw-r--r--ash/wm/cursor_manager.h11
-rw-r--r--ash/wm/image_cursors.cc123
-rw-r--r--ash/wm/image_cursors.h43
-rw-r--r--ash/wm/toplevel_window_event_handler.cc6
-rw-r--r--chrome/browser/ui/ash/ash_init.cc9
-rw-r--r--ui/aura/client/cursor_client.h3
-rw-r--r--ui/aura/client/drag_drop_client.h5
-rw-r--r--ui/aura/desktop/desktop_cursor_client.cc4
-rw-r--r--ui/aura/desktop/desktop_cursor_client.h1
-rw-r--r--ui/aura/root_window.cc22
-rw-r--r--ui/aura/root_window.h12
-rw-r--r--ui/aura/root_window_host_linux.cc315
-rw-r--r--ui/aura/root_window_host_linux.h3
-rw-r--r--ui/aura/root_window_host_win.cc1
-rw-r--r--ui/aura/shared/compound_event_filter.cc25
-rw-r--r--ui/aura/shared/compound_event_filter_unittest.cc3
-rw-r--r--ui/base/cursor/cursor.cc20
-rw-r--r--ui/base/cursor/cursor.h15
-rw-r--r--ui/base/cursor/cursor_loader.h61
-rw-r--r--ui/base/cursor/cursor_loader_win.cc40
-rw-r--r--ui/base/cursor/cursor_loader_win.h35
-rw-r--r--ui/base/cursor/cursor_loader_x11.cc203
-rw-r--r--ui/base/cursor/cursor_loader_x11.h58
-rw-r--r--ui/base/x/events_x.cc4
-rw-r--r--ui/base/x/x11_util.cc41
-rw-r--r--ui/base/x/x11_util.h24
-rw-r--r--ui/ui.gyp7
-rw-r--r--webkit/glue/webcursor_aura.cc2
35 files changed, 773 insertions, 370 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp
index e4b0877..8d1f53b 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -274,6 +274,8 @@
'wm/gestures/system_pinch_handler.h',
'wm/gestures/two_finger_drag_handler.cc',
'wm/gestures/two_finger_drag_handler.h',
+ 'wm/image_cursors.cc',
+ 'wm/image_cursors.h',
'wm/image_grid.cc',
'wm/image_grid.h',
'wm/maximize_bubble_controller.cc',
diff --git a/ash/display/mouse_cursor_event_filter.cc b/ash/display/mouse_cursor_event_filter.cc
index 2973ef8..469db41 100644
--- a/ash/display/mouse_cursor_event_filter.cc
+++ b/ash/display/mouse_cursor_event_filter.cc
@@ -153,6 +153,8 @@ bool MouseCursorEventFilter::WarpMouseCursorIfNecessary(
if (dst_root->bounds().Contains(point_in_dst_screen)) {
DCHECK_NE(dst_root, current_root);
dst_root->MoveCursorTo(point_in_dst_screen);
+ ash::Shell::GetInstance()->cursor_manager()->SetDeviceScaleFactor(
+ dst_root->AsRootWindowHostDelegate()->GetDeviceScaleFactor());
return true;
}
return false;
diff --git a/ash/drag_drop/drag_drop_controller.cc b/ash/drag_drop/drag_drop_controller.cc
index eb33f3d..acecc81 100644
--- a/ash/drag_drop/drag_drop_controller.cc
+++ b/ash/drag_drop/drag_drop_controller.cc
@@ -62,7 +62,6 @@ int DragDropController::StartDragAndDrop(const ui::OSExchangeData& data,
int operation) {
DCHECK(!IsDragDropInProgress());
- drag_cursor_ = ui::kCursorPointer;
drag_drop_tracker_.reset(new DragDropTracker(root_window));
drag_data_ = &data;
@@ -128,7 +127,6 @@ void DragDropController::DragUpdate(aura::Window* target,
cursor = ui::kCursorAlias;
else if (op & ui::DragDropTypes::DRAG_MOVE)
cursor = ui::kCursorMove;
- drag_cursor_ = cursor;
ash::Shell::GetInstance()->cursor_manager()->SetCursor(cursor);
}
}
@@ -145,7 +143,6 @@ void DragDropController::DragUpdate(aura::Window* target,
void DragDropController::Drop(aura::Window* target,
const ui::LocatedEvent& event) {
- drag_cursor_ = ui::kCursorPointer;
ash::Shell::GetInstance()->cursor_manager()->SetCursor(ui::kCursorPointer);
aura::client::DragDropDelegate* delegate = NULL;
@@ -175,7 +172,6 @@ void DragDropController::Drop(aura::Window* target,
}
void DragDropController::DragCancel() {
- drag_cursor_ = ui::kCursorPointer;
ash::Shell::GetInstance()->cursor_manager()->SetCursor(ui::kCursorPointer);
// |drag_window_| can be NULL if we have just started the drag and have not
@@ -197,10 +193,6 @@ bool DragDropController::IsDragDropInProgress() {
return !!drag_drop_tracker_.get();
}
-gfx::NativeCursor DragDropController::GetDragCursor() {
- return drag_cursor_;
-}
-
bool DragDropController::PreHandleKeyEvent(aura::Window* target,
ui::KeyEvent* event) {
if (IsDragDropInProgress() && event->key_code() == ui::VKEY_ESCAPE) {
diff --git a/ash/drag_drop/drag_drop_controller.h b/ash/drag_drop/drag_drop_controller.h
index d138ef6..59f1f32 100644
--- a/ash/drag_drop/drag_drop_controller.h
+++ b/ash/drag_drop/drag_drop_controller.h
@@ -59,7 +59,6 @@ class ASH_EXPORT DragDropController
const ui::LocatedEvent& event) OVERRIDE;
virtual void DragCancel() OVERRIDE;
virtual bool IsDragDropInProgress() OVERRIDE;
- virtual gfx::NativeCursor GetDragCursor() OVERRIDE;
// Overridden from aura::EventFilter:
virtual bool PreHandleKeyEvent(aura::Window* target,
@@ -92,7 +91,6 @@ class ASH_EXPORT DragDropController
gfx::Point drag_image_offset_;
const ui::OSExchangeData* drag_data_;
int drag_operation_;
- gfx::NativeCursor drag_cursor_;
// Window that is currently under the drag cursor.
aura::Window* drag_window_;
diff --git a/ash/extended_desktop_unittest.cc b/ash/extended_desktop_unittest.cc
index b1e9583..20e4115 100644
--- a/ash/extended_desktop_unittest.cc
+++ b/ash/extended_desktop_unittest.cc
@@ -165,17 +165,17 @@ TEST_F(ExtendedDesktopTest, SystemModal) {
TEST_F(ExtendedDesktopTest, TestCursor) {
UpdateDisplay("1000x600,600x400");
- Shell::GetInstance()->ShowCursor(false);
+ Shell::GetInstance()->cursor_manager()->ShowCursor(false);
Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
EXPECT_FALSE(root_windows[0]->cursor_shown());
EXPECT_FALSE(root_windows[1]->cursor_shown());
- Shell::GetInstance()->ShowCursor(true);
+ Shell::GetInstance()->cursor_manager()->ShowCursor(true);
EXPECT_TRUE(root_windows[0]->cursor_shown());
EXPECT_TRUE(root_windows[1]->cursor_shown());
EXPECT_EQ(ui::kCursorPointer, root_windows[0]->last_cursor().native_type());
EXPECT_EQ(ui::kCursorPointer, root_windows[1]->last_cursor().native_type());
- Shell::GetInstance()->SetCursor(ui::kCursorCopy);
+ Shell::GetInstance()->cursor_manager()->SetCursor(ui::kCursorCopy);
EXPECT_EQ(ui::kCursorCopy, root_windows[0]->last_cursor().native_type());
EXPECT_EQ(ui::kCursorCopy, root_windows[1]->last_cursor().native_type());
}
diff --git a/ash/shell.cc b/ash/shell.cc
index 6c26a09..ebfa9eb 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -372,6 +372,9 @@ void Shell::Init() {
aura::RootWindow* root_window = display_controller_->GetPrimaryRootWindow();
active_root_window_ = root_window;
+ cursor_manager_.SetDeviceScaleFactor(
+ root_window->AsRootWindowHostDelegate()->GetDeviceScaleFactor());
+
#if !defined(OS_MACOSX)
nested_dispatcher_controller_.reset(new NestedDispatcherController);
accelerator_controller_.reset(new AcceleratorController);
diff --git a/ash/wm/cursor_manager.cc b/ash/wm/cursor_manager.cc
index 1ebc72b..3afee4b 100644
--- a/ash/wm/cursor_manager.cc
+++ b/ash/wm/cursor_manager.cc
@@ -5,8 +5,10 @@
#include "ash/wm/cursor_manager.h"
#include "ash/wm/cursor_delegate.h"
+#include "ash/wm/image_cursors.h"
#include "base/logging.h"
#include "ui/aura/env.h"
+#include "ui/base/cursor/cursor.h"
namespace ash {
@@ -15,7 +17,9 @@ CursorManager::CursorManager()
cursor_lock_count_(0),
did_cursor_change_(false),
cursor_to_set_on_unlock_(0),
- cursor_visible_(true) {
+ cursor_visible_(true),
+ current_cursor_(ui::kCursorNone),
+ image_cursors_(new ImageCursors) {
}
CursorManager::~CursorManager() {
@@ -42,7 +46,7 @@ void CursorManager::UnlockCursor() {
void CursorManager::SetCursor(gfx::NativeCursor cursor) {
if (cursor_lock_count_ == 0) {
if (delegate_)
- delegate_->SetCursor(cursor);
+ SetCursorInternal(cursor);
} else {
cursor_to_set_on_unlock_ = cursor;
did_cursor_change_ = true;
@@ -59,4 +63,20 @@ bool CursorManager::IsCursorVisible() const {
return cursor_visible_;
}
+void CursorManager::SetDeviceScaleFactor(float device_scale_factor) {
+ if (image_cursors_->GetDeviceScaleFactor() == device_scale_factor)
+ return;
+ image_cursors_->SetDeviceScaleFactor(device_scale_factor);
+ SetCursorInternal(current_cursor_);
+}
+
+void CursorManager::SetCursorInternal(gfx::NativeCursor cursor) {
+ DCHECK(delegate_);
+ current_cursor_ = cursor;
+ image_cursors_->SetPlatformCursor(&current_cursor_);
+ current_cursor_.set_device_scale_factor(
+ image_cursors_->GetDeviceScaleFactor());
+ delegate_->SetCursor(current_cursor_);
+}
+
} // namespace ash
diff --git a/ash/wm/cursor_manager.h b/ash/wm/cursor_manager.h
index 9f2cc8b..f5b5548 100644
--- a/ash/wm/cursor_manager.h
+++ b/ash/wm/cursor_manager.h
@@ -7,12 +7,14 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
#include "ui/aura/aura_export.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/gfx/native_widget_types.h"
namespace ash {
class CursorDelegate;
+class ImageCursors;
// This class controls the visibility and the type of the cursor.
// The cursor type can be locked so that the type stays the same
@@ -33,11 +35,15 @@ class CursorManager : public aura::client::CursorClient {
// Shows or hides the cursor.
bool cursor_visible() const { return cursor_visible_; }
+ // Overridden from aura::client::CursorClient:
virtual void SetCursor(gfx::NativeCursor) OVERRIDE;
virtual void ShowCursor(bool show) OVERRIDE;
virtual bool IsCursorVisible() const OVERRIDE;
+ virtual void SetDeviceScaleFactor(float device_scale_factor) OVERRIDE;
private:
+ void SetCursorInternal(gfx::NativeCursor cursor);
+
CursorDelegate* delegate_;
// Number of times LockCursor() has been invoked without a corresponding
@@ -54,6 +60,11 @@ class CursorManager : public aura::client::CursorClient {
// Is cursor visible?
bool cursor_visible_;
+ // The cursor currently set.
+ gfx::NativeCursor current_cursor_;
+
+ scoped_ptr<ImageCursors> image_cursors_;
+
DISALLOW_COPY_AND_ASSIGN(CursorManager);
};
diff --git a/ash/wm/image_cursors.cc b/ash/wm/image_cursors.cc
new file mode 100644
index 0000000..b0ec3f5
--- /dev/null
+++ b/ash/wm/image_cursors.cc
@@ -0,0 +1,123 @@
+// 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/image_cursors.h"
+
+#include "base/logging.h"
+#include "ui/base/cursor/cursor_loader.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/gfx/point.h"
+#include "grit/ui_resources.h"
+
+namespace {
+
+const int kAnimatedCursorFrameDelayMs = 25;
+
+struct HotPoint {
+ int x;
+ int y;
+};
+
+struct CursorData {
+ int id;
+ int resource_id;
+ HotPoint hot_1x;
+ HotPoint hot_2x;
+};
+
+// TODO(oshima): Remove this comment (http://crbug.com/141586).
+// The cursor's hot points are defined in chromeos cursor images at:
+// http://folder/kuscher/projects/Chrome_OS/Pointers/focuspoint
+const CursorData kImageCursors[] = {
+ {ui::kCursorNull, IDR_AURA_CURSOR_PTR, {4, 4}, {8, 9}},
+ {ui::kCursorPointer, IDR_AURA_CURSOR_PTR, {4, 4}, {8, 9}},
+ {ui::kCursorNoDrop, IDR_AURA_CURSOR_NO_DROP, {4, 4}, {8, 9}},
+ {ui::kCursorNotAllowed, IDR_AURA_CURSOR_NO_DROP, {4, 4}, {8, 9}},
+ {ui::kCursorCopy, IDR_AURA_CURSOR_COPY, {4, 4}, {8, 9}},
+ {ui::kCursorHand, IDR_AURA_CURSOR_HAND, {9, 4}, {19, 8}},
+ {ui::kCursorMove, IDR_AURA_CURSOR_MOVE, {11, 11}, {23, 23}},
+ {ui::kCursorNorthEastResize, IDR_AURA_CURSOR_NORTH_EAST_RESIZE,
+ {12, 11}, {25, 23}},
+ {ui::kCursorSouthWestResize, IDR_AURA_CURSOR_SOUTH_WEST_RESIZE,
+ {12, 11}, {25, 23}},
+ {ui::kCursorSouthEastResize, IDR_AURA_CURSOR_SOUTH_EAST_RESIZE,
+ {11, 11}, {24, 23}},
+ {ui::kCursorNorthWestResize, IDR_AURA_CURSOR_NORTH_WEST_RESIZE,
+ {11, 11}, {24, 23}},
+ {ui::kCursorNorthResize, IDR_AURA_CURSOR_NORTH_RESIZE, {11, 12}, {23, 23}},
+ {ui::kCursorSouthResize, IDR_AURA_CURSOR_SOUTH_RESIZE, {11, 12}, {23, 23}},
+ {ui::kCursorEastResize, IDR_AURA_CURSOR_EAST_RESIZE, {12, 11}, {25, 23}},
+ {ui::kCursorWestResize, IDR_AURA_CURSOR_WEST_RESIZE, {12, 11}, {25, 23}},
+ {ui::kCursorIBeam, IDR_AURA_CURSOR_IBEAM, {12, 12}, {24, 25}},
+ {ui::kCursorAlias, IDR_AURA_CURSOR_ALIAS, {8, 6}, {15, 11}},
+ {ui::kCursorCell, IDR_AURA_CURSOR_CELL, {11, 11}, {24, 23}},
+ {ui::kCursorContextMenu, IDR_AURA_CURSOR_CONTEXT_MENU, {4, 4}, {8, 9}},
+ {ui::kCursorCross, IDR_AURA_CURSOR_CROSSHAIR, {12, 12}, {25, 23}},
+ {ui::kCursorHelp, IDR_AURA_CURSOR_HELP, {4, 4}, {8, 9}},
+ {ui::kCursorVerticalText, IDR_AURA_CURSOR_XTERM_HORIZ, {12, 11}, {26, 23}},
+ {ui::kCursorZoomIn, IDR_AURA_CURSOR_ZOOM_IN, {10, 10}, {20, 20}},
+ {ui::kCursorZoomOut, IDR_AURA_CURSOR_ZOOM_OUT, {10, 10}, {20, 20}},
+ {ui::kCursorRowResize, IDR_AURA_CURSOR_ROW_RESIZE, {11, 12}, {23, 23}},
+ {ui::kCursorColumnResize, IDR_AURA_CURSOR_COL_RESIZE, {12, 11}, {25, 23}},
+ {ui::kCursorEastWestResize, IDR_AURA_CURSOR_EAST_WEST_RESIZE,
+ {12, 11}, {25, 23}},
+ {ui::kCursorNorthSouthResize, IDR_AURA_CURSOR_NORTH_SOUTH_RESIZE,
+ {11, 12}, {23, 23}},
+ {ui::kCursorNorthEastSouthWestResize,
+ IDR_AURA_CURSOR_NORTH_EAST_SOUTH_WEST_RESIZE, {12, 11}, {25, 23}},
+ {ui::kCursorNorthWestSouthEastResize,
+ IDR_AURA_CURSOR_NORTH_WEST_SOUTH_EAST_RESIZE, {11, 11}, {24, 23}},
+ {ui::kCursorGrab, IDR_AURA_CURSOR_GRAB, {8, 5}, {16, 10}},
+ {ui::kCursorGrabbing, IDR_AURA_CURSOR_GRABBING, {9, 9}, {18, 18}},
+};
+
+const CursorData kAnimatedCursors[] = {
+ {ui::kCursorWait, IDR_THROBBER, {7, 7}, {14, 14}},
+ {ui::kCursorProgress, IDR_THROBBER, {7, 7}, {14, 14}},
+};
+
+} // namespace
+
+namespace ash {
+
+ImageCursors::ImageCursors()
+ : cursor_loader_(ui::CursorLoader::Create()) {
+}
+
+ImageCursors::~ImageCursors() {
+}
+
+float ImageCursors::GetDeviceScaleFactor() const {
+ return cursor_loader_->device_scale_factor();
+}
+
+void ImageCursors::SetDeviceScaleFactor(float device_scale_factor) {
+ if (GetDeviceScaleFactor() == device_scale_factor)
+ return;
+
+ cursor_loader_->UnloadAll();
+ cursor_loader_->set_device_scale_factor(device_scale_factor);
+
+ for (size_t i = 0; i < arraysize(kImageCursors); ++i) {
+ const HotPoint& hot = device_scale_factor == 1.0f ?
+ kImageCursors[i].hot_1x : kImageCursors[i].hot_2x;
+ cursor_loader_->LoadImageCursor(kImageCursors[i].id,
+ kImageCursors[i].resource_id,
+ gfx::Point(hot.x, hot.y));
+ }
+ for (size_t i = 0; i < arraysize(kAnimatedCursors); ++i) {
+ const HotPoint& hot = device_scale_factor == 1.0f ?
+ kAnimatedCursors[i].hot_1x : kAnimatedCursors[i].hot_2x;
+ cursor_loader_->LoadAnimatedCursor(kAnimatedCursors[i].id,
+ kAnimatedCursors[i].resource_id,
+ gfx::Point(hot.x, hot.y),
+ kAnimatedCursorFrameDelayMs);
+ }
+}
+
+void ImageCursors::SetPlatformCursor(gfx::NativeCursor* cursor) {
+ cursor_loader_->SetPlatformCursor(cursor);
+}
+
+} // namespace ash
diff --git a/ash/wm/image_cursors.h b/ash/wm/image_cursors.h
new file mode 100644
index 0000000..a1a7c41
--- /dev/null
+++ b/ash/wm/image_cursors.h
@@ -0,0 +1,43 @@
+// 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_WM_IMAGE_CURSORS_H_
+#define ASH_WM_IMAGE_CURSORS_H_
+
+#include "ash/ash_export.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/native_widget_types.h"
+
+namespace ui {
+class CursorLoader;
+}
+
+namespace ash {
+
+// A utility class that provides cursors for NativeCursors for which we have
+// image resources.
+class ASH_EXPORT ImageCursors {
+ public:
+ ImageCursors();
+ ~ImageCursors();
+
+ // Returns the device scale factor of cursors.
+ float GetDeviceScaleFactor() const;
+
+ // Sets the device scale factor of the cursors with |device_scale_factor| and
+ // reloads the cursor images if necessary.
+ void SetDeviceScaleFactor(float device_scale_factor);
+
+ // Sets the platform cursor based on the native type of |cursor|.
+ void SetPlatformCursor(gfx::NativeCursor* cursor);
+
+ private:
+ scoped_ptr<ui::CursorLoader> cursor_loader_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImageCursors);
+};
+
+} // namespace ash
+
+#endif // ASH_WM_IMAGE_CURSORS_H_
diff --git a/ash/wm/toplevel_window_event_handler.cc b/ash/wm/toplevel_window_event_handler.cc
index aa0f754..ce4be53 100644
--- a/ash/wm/toplevel_window_event_handler.cc
+++ b/ash/wm/toplevel_window_event_handler.cc
@@ -14,6 +14,7 @@
#include "base/message_loop.h"
#include "base/run_loop.h"
#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/cursor_client.h"
#include "ui/aura/env.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
@@ -276,7 +277,10 @@ aura::client::WindowMoveResult ToplevelWindowEventHandler::RunMoveLoop(
root_window, source->parent(), &drag_location);
}
CreateScopedWindowResizer(source, drag_location, HTCAPTION);
- source->GetRootWindow()->SetCursor(ui::kCursorPointer);
+ aura::client::CursorClient* cursor_client =
+ aura::client::GetCursorClient(root_window);
+ if (cursor_client)
+ cursor_client->SetCursor(ui::kCursorPointer);
#if !defined(OS_MACOSX)
MessageLoopForUI* loop = MessageLoopForUI::current();
MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
diff --git a/chrome/browser/ui/ash/ash_init.cc b/chrome/browser/ui/ash/ash_init.cc
index 9462a66..5b55217 100644
--- a/chrome/browser/ui/ash/ash_init.cc
+++ b/chrome/browser/ui/ash/ash_init.cc
@@ -31,6 +31,7 @@
#include "chrome/browser/ui/ash/ime_controller_chromeos.h"
#include "chrome/browser/ui/ash/keyboard_brightness_controller_chromeos.h"
#include "chrome/browser/ui/ash/volume_controller_chromeos.h"
+#include "ui/base/x/x11_util.h"
#endif
@@ -48,14 +49,18 @@ void OpenAsh() {
switches::kAuraHostWindowUseFullscreen);
#if defined(OS_CHROMEOS)
- if (base::chromeos::IsRunningOnChromeOS())
+ if (base::chromeos::IsRunningOnChromeOS()) {
use_fullscreen = true;
+ // Hides the cursor outside of the Aura root window. The cursor will be
+ // drawn within the Aura root window, and it'll remain hidden after the
+ // Aura window is closed.
+ ui::HideHostCursor();
+ }
#endif
if (use_fullscreen) {
aura::DisplayManager::set_use_fullscreen_host_window(true);
#if defined(OS_CHROMEOS)
- aura::RootWindow::set_hide_host_cursor(true);
// Hide the mouse cursor completely at boot.
if (!chromeos::UserManager::Get()->IsUserLoggedIn())
ash::Shell::set_initially_hide_cursor(true);
diff --git a/ui/aura/client/cursor_client.h b/ui/aura/client/cursor_client.h
index 418c559..ecf67ee 100644
--- a/ui/aura/client/cursor_client.h
+++ b/ui/aura/client/cursor_client.h
@@ -24,6 +24,9 @@ class AURA_EXPORT CursorClient {
// Gets whether the cursor is visible.
virtual bool IsCursorVisible() const = 0;
+ // Sets the device scale factor of the cursor.
+ virtual void SetDeviceScaleFactor(float device_scale_factor) = 0;
+
protected:
virtual ~CursorClient() {}
};
diff --git a/ui/aura/client/drag_drop_client.h b/ui/aura/client/drag_drop_client.h
index 25c662f..bb28184 100644
--- a/ui/aura/client/drag_drop_client.h
+++ b/ui/aura/client/drag_drop_client.h
@@ -48,11 +48,6 @@ class AURA_EXPORT DragDropClient {
// Returns true if a drag and drop session is in progress.
virtual bool IsDragDropInProgress() = 0;
-
- // Returns the current cursor according to the appropriate drag effect. This
- // should only be called if IsDragDropInProgress() returns true. If it is
- // called otherwise, the returned cursor is arbitrary.
- virtual gfx::NativeCursor GetDragCursor() = 0;
};
AURA_EXPORT void SetDragDropClient(RootWindow* root_window,
diff --git a/ui/aura/desktop/desktop_cursor_client.cc b/ui/aura/desktop/desktop_cursor_client.cc
index d44cb32..70bb4aa 100644
--- a/ui/aura/desktop/desktop_cursor_client.cc
+++ b/ui/aura/desktop/desktop_cursor_client.cc
@@ -27,4 +27,8 @@ bool DesktopCursorClient::IsCursorVisible() const {
return root_window_->cursor_shown();
}
+void DesktopCursorClient::SetDeviceScaleFactor(float device_scale_factor) {
+ // TODO(ben|erg): Use the device scale factor set here for the cursor.
+}
+
} // namespace aura
diff --git a/ui/aura/desktop/desktop_cursor_client.h b/ui/aura/desktop/desktop_cursor_client.h
index a4315ed..9ce0526 100644
--- a/ui/aura/desktop/desktop_cursor_client.h
+++ b/ui/aura/desktop/desktop_cursor_client.h
@@ -24,6 +24,7 @@ class AURA_EXPORT DesktopCursorClient : public client::CursorClient {
virtual void SetCursor(gfx::NativeCursor cursor) OVERRIDE;
virtual void ShowCursor(bool show) OVERRIDE;
virtual bool IsCursorVisible() const OVERRIDE;
+ virtual void SetDeviceScaleFactor(float device_scale_factor) OVERRIDE;
private:
aura::RootWindow* root_window_;
diff --git a/ui/aura/root_window.cc b/ui/aura/root_window.cc
index 7662cfe..b261a2a 100644
--- a/ui/aura/root_window.cc
+++ b/ui/aura/root_window.cc
@@ -15,7 +15,7 @@
#include "ui/aura/aura_switches.h"
#include "ui/aura/client/activation_client.h"
#include "ui/aura/client/capture_client.h"
-#include "ui/aura/client/drag_drop_client.h"
+#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/event_client.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/display_manager.h"
@@ -110,8 +110,6 @@ void CompositorLock::CancelLock() {
root_window_ = NULL;
}
-bool RootWindow::hide_host_cursor_ = false;
-
RootWindow::CreateParams::CreateParams(const gfx::Rect& a_initial_bounds)
: initial_bounds(a_initial_bounds),
host(NULL) {
@@ -246,11 +244,6 @@ gfx::Point RootWindow::GetHostOrigin() const {
}
void RootWindow::SetCursor(gfx::NativeCursor cursor) {
- // If a drag is in progress, the DragDropClient should override the cursor.
- client::DragDropClient* dnd_client = client::GetDragDropClient(this);
- if (dnd_client && dnd_client->IsDragDropInProgress())
- cursor = dnd_client->GetDragCursor();
-
last_cursor_ = cursor;
// A lot of code seems to depend on NULL cursors actually showing an arrow,
// so just pass everything along to the host.
@@ -529,11 +522,20 @@ void RootWindow::OnCompositingAborted(ui::Compositor*) {
void RootWindow::OnDeviceScaleFactorChanged(
float device_scale_factor) {
- if (cursor_shown_)
+ const bool cursor_is_in_bounds =
+ GetBoundsInScreen().Contains(Env::GetInstance()->last_mouse_location());
+ if (cursor_is_in_bounds && cursor_shown_)
ShowCursor(false);
host_->OnDeviceScaleFactorChanged(device_scale_factor);
Window::OnDeviceScaleFactorChanged(device_scale_factor);
- if (cursor_shown_)
+ // Update the device scale factor of the cursor client only when the last
+ // mouse location is on this root window.
+ if (cursor_is_in_bounds) {
+ client::CursorClient* cursor_client = client::GetCursorClient(this);
+ if (cursor_client)
+ cursor_client->SetDeviceScaleFactor(device_scale_factor);
+ }
+ if (cursor_is_in_bounds && cursor_shown_)
ShowCursor(true);
}
diff --git a/ui/aura/root_window.h b/ui/aura/root_window.h
index cdc05c0..869802d 100644
--- a/ui/aura/root_window.h
+++ b/ui/aura/root_window.h
@@ -101,13 +101,6 @@ class AURA_EXPORT RootWindow : public ui::CompositorDelegate,
static RootWindow* GetForAcceleratedWidget(gfx::AcceleratedWidget widget);
- static void set_hide_host_cursor(bool hide) {
- hide_host_cursor_ = hide;
- }
- static bool hide_host_cursor() {
- return hide_host_cursor_;
- }
-
ui::Compositor* compositor() { return compositor_.get(); }
gfx::NativeCursor last_cursor() const { return last_cursor_; }
Window* mouse_pressed_handler() { return mouse_pressed_handler_; }
@@ -370,11 +363,6 @@ class AURA_EXPORT RootWindow : public ui::CompositorDelegate,
scoped_ptr<RootWindowHost> host_;
- // If set before the RootWindow is created, the cursor will be drawn within
- // the Aura root window but hidden outside of it, and it'll remain hidden
- // after the Aura window is closed.
- static bool hide_host_cursor_;
-
// Used to schedule painting.
base::WeakPtrFactory<RootWindow> schedule_paint_factory_;
diff --git a/ui/aura/root_window_host_linux.cc b/ui/aura/root_window_host_linux.cc
index a0c416f..8edb6ba 100644
--- a/ui/aura/root_window_host_linux.cc
+++ b/ui/aura/root_window_host_linux.cc
@@ -17,8 +17,8 @@
#include "base/message_pump_aurax11.h"
#include "base/stl_util.h"
#include "base/stringprintf.h"
-#include "grit/ui_resources.h"
#include "ui/aura/client/capture_client.h"
+#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/client/user_action_client.h"
#include "ui/aura/env.h"
@@ -26,7 +26,6 @@
#include "ui/base/cursor/cursor.h"
#include "ui/base/events/event.h"
#include "ui/base/keycodes/keyboard_codes.h"
-#include "ui/base/resource/resource_bundle.h"
#include "ui/base/touch/touch_factory.h"
#include "ui/base/ui_base_switches.h"
#include "ui/base/view_prop.h"
@@ -34,8 +33,6 @@
#include "ui/base/x/x11_util.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/codec/png_codec.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/screen.h"
#if defined(OS_CHROMEOS)
@@ -53,8 +50,6 @@ namespace {
const int kBackMouseButton = 8;
const int kForwardMouseButton = 9;
-const int kAnimatedCursorFrameDelayMs = 25;
-
// These are the same values that are used to calibrate touch events in
// |CalibrateTouchCoordinates| (in ui/base/x/events_x.cc).
// TODO(sad|skuhne): Remove the duplication of values (http://crbug.com/147605)
@@ -124,75 +119,6 @@ void CheckXEventForConsistency(XEvent* xevent) {
#endif // defined(USE_XI2_MT) && !defined(NDEBUG)
}
-// Returns X font cursor shape from an Aura cursor.
-int CursorShapeFromNative(gfx::NativeCursor native_cursor) {
- switch (native_cursor.native_type()) {
- case ui::kCursorMiddlePanning:
- return XC_fleur;
- case ui::kCursorEastPanning:
- return XC_sb_right_arrow;
- case ui::kCursorNorthPanning:
- return XC_sb_up_arrow;
- case ui::kCursorNorthEastPanning:
- return XC_top_right_corner;
- case ui::kCursorNorthWestPanning:
- return XC_top_left_corner;
- case ui::kCursorSouthPanning:
- return XC_sb_down_arrow;
- case ui::kCursorSouthEastPanning:
- return XC_bottom_right_corner;
- case ui::kCursorSouthWestPanning:
- return XC_bottom_left_corner;
- case ui::kCursorWestPanning:
- return XC_sb_left_arrow;
- case ui::kCursorNone:
- // TODO(jamescook): Need cursors for these. crbug.com/111650
- return XC_left_ptr;
-
- case ui::kCursorNull:
- case ui::kCursorPointer:
- case ui::kCursorNoDrop:
- case ui::kCursorNotAllowed:
- case ui::kCursorCopy:
- case ui::kCursorMove:
- case ui::kCursorEastResize:
- case ui::kCursorNorthResize:
- case ui::kCursorSouthResize:
- case ui::kCursorWestResize:
- case ui::kCursorNorthEastResize:
- case ui::kCursorNorthWestResize:
- case ui::kCursorSouthWestResize:
- case ui::kCursorSouthEastResize:
- case ui::kCursorIBeam:
- case ui::kCursorAlias:
- case ui::kCursorCell:
- case ui::kCursorContextMenu:
- case ui::kCursorCross:
- case ui::kCursorHelp:
- case ui::kCursorWait:
- case ui::kCursorNorthSouthResize:
- case ui::kCursorEastWestResize:
- case ui::kCursorNorthEastSouthWestResize:
- case ui::kCursorNorthWestSouthEastResize:
- case ui::kCursorProgress:
- case ui::kCursorColumnResize:
- case ui::kCursorRowResize:
- case ui::kCursorVerticalText:
- case ui::kCursorZoomIn:
- case ui::kCursorZoomOut:
- case ui::kCursorGrab:
- case ui::kCursorGrabbing:
- NOTREACHED() << "Cursor (" << native_cursor.native_type() << ") should "
- << "have an image asset.";
- return XC_left_ptr;
- case ui::kCursorCustom:
- NOTREACHED();
- return XC_left_ptr;
- }
- NOTREACHED();
- return XC_left_ptr;
-}
-
// Coalesce all pending motion events (touch or mouse) that are at the top of
// the queue, and return the number eliminated, storing the last one in
// |last_event|.
@@ -354,200 +280,6 @@ bool ShouldSendCharEventForKeyboardCode(ui::KeyboardCode keycode) {
} // namespace
-// A utility class that provides X Cursor for NativeCursors for which we have
-// image resources.
-class RootWindowHostLinux::ImageCursors {
- public:
- ImageCursors() : scale_factor_(0.0) {
- }
-
- void Reload(float scale_factor) {
- if (scale_factor_ == scale_factor)
- return;
- scale_factor_ = scale_factor;
- UnloadAll();
- // The cursor's hot points are defined in chromeos cursor images at:
- // http://folder/kuscher/projects/Chrome_OS/Pointers/focuspoint
- LoadImageCursor(ui::kCursorNull, IDR_AURA_CURSOR_PTR,
- gfx::Point(4, 4), gfx::Point(8, 9));
- LoadImageCursor(ui::kCursorPointer, IDR_AURA_CURSOR_PTR,
- gfx::Point(4, 4), gfx::Point(8, 9));
- LoadImageCursor(ui::kCursorNoDrop, IDR_AURA_CURSOR_NO_DROP,
- gfx::Point(4, 4), gfx::Point(8, 9));
- LoadImageCursor(ui::kCursorNotAllowed, IDR_AURA_CURSOR_NO_DROP,
- gfx::Point(4, 4), gfx::Point(8, 9));
- LoadImageCursor(ui::kCursorCopy, IDR_AURA_CURSOR_COPY,
- gfx::Point(4, 4), gfx::Point(8, 9));
- LoadImageCursor(ui::kCursorHand, IDR_AURA_CURSOR_HAND,
- gfx::Point(9, 4), gfx::Point(19, 8));
- LoadImageCursor(ui::kCursorMove, IDR_AURA_CURSOR_MOVE,
- gfx::Point(11, 11), gfx::Point(23, 23));
- LoadImageCursor(ui::kCursorNorthEastResize,
- IDR_AURA_CURSOR_NORTH_EAST_RESIZE,
- gfx::Point(12, 11), gfx::Point(25, 23));
- LoadImageCursor(ui::kCursorSouthWestResize,
- IDR_AURA_CURSOR_SOUTH_WEST_RESIZE,
- gfx::Point(12, 11), gfx::Point(25, 23));
- LoadImageCursor(ui::kCursorSouthEastResize,
- IDR_AURA_CURSOR_SOUTH_EAST_RESIZE,
- gfx::Point(11, 11), gfx::Point(24, 23));
- LoadImageCursor(ui::kCursorNorthWestResize,
- IDR_AURA_CURSOR_NORTH_WEST_RESIZE,
- gfx::Point(11, 11), gfx::Point(24, 23));
- LoadImageCursor(ui::kCursorNorthResize, IDR_AURA_CURSOR_NORTH_RESIZE,
- gfx::Point(11, 12), gfx::Point(23, 23));
- LoadImageCursor(ui::kCursorSouthResize, IDR_AURA_CURSOR_SOUTH_RESIZE,
- gfx::Point(11, 12), gfx::Point(23, 23));
- LoadImageCursor(ui::kCursorEastResize, IDR_AURA_CURSOR_EAST_RESIZE,
- gfx::Point(12, 11), gfx::Point(25, 23));
- LoadImageCursor(ui::kCursorWestResize, IDR_AURA_CURSOR_WEST_RESIZE,
- gfx::Point(12, 11), gfx::Point(25, 23));
- LoadImageCursor(ui::kCursorIBeam, IDR_AURA_CURSOR_IBEAM,
- gfx::Point(12, 12), gfx::Point(24, 25));
- LoadImageCursor(ui::kCursorAlias, IDR_AURA_CURSOR_ALIAS,
- gfx::Point(8, 6), gfx::Point(15, 11));
- LoadImageCursor(ui::kCursorCell, IDR_AURA_CURSOR_CELL,
- gfx::Point(11, 11), gfx::Point(24, 23));
- LoadImageCursor(ui::kCursorContextMenu, IDR_AURA_CURSOR_CONTEXT_MENU,
- gfx::Point(4, 4), gfx::Point(8, 9));
- LoadImageCursor(ui::kCursorCross, IDR_AURA_CURSOR_CROSSHAIR,
- gfx::Point(12, 12), gfx::Point(25, 23));
- LoadImageCursor(ui::kCursorHelp, IDR_AURA_CURSOR_HELP,
- gfx::Point(4, 4), gfx::Point(8, 9));
- LoadImageCursor(ui::kCursorVerticalText, IDR_AURA_CURSOR_XTERM_HORIZ,
- gfx::Point(12, 11), gfx::Point(26, 23));
- LoadImageCursor(ui::kCursorZoomIn, IDR_AURA_CURSOR_ZOOM_IN,
- gfx::Point(10, 10), gfx::Point(20, 20));
- LoadImageCursor(ui::kCursorZoomOut, IDR_AURA_CURSOR_ZOOM_OUT,
- gfx::Point(10, 10), gfx::Point(20, 20));
- LoadImageCursor(ui::kCursorRowResize, IDR_AURA_CURSOR_ROW_RESIZE,
- gfx::Point(11, 12), gfx::Point(23, 23));
- LoadImageCursor(ui::kCursorColumnResize, IDR_AURA_CURSOR_COL_RESIZE,
- gfx::Point(12, 11), gfx::Point(25, 23));
- LoadImageCursor(ui::kCursorEastWestResize, IDR_AURA_CURSOR_EAST_WEST_RESIZE,
- gfx::Point(12, 11), gfx::Point(25, 23));
- LoadImageCursor(ui::kCursorNorthSouthResize,
- IDR_AURA_CURSOR_NORTH_SOUTH_RESIZE,
- gfx::Point(11, 12), gfx::Point(23, 23));
- LoadImageCursor(ui::kCursorNorthEastSouthWestResize,
- IDR_AURA_CURSOR_NORTH_EAST_SOUTH_WEST_RESIZE,
- gfx::Point(12, 11), gfx::Point(25, 23));
- LoadImageCursor(ui::kCursorNorthWestSouthEastResize,
- IDR_AURA_CURSOR_NORTH_WEST_SOUTH_EAST_RESIZE,
- gfx::Point(11, 11), gfx::Point(24, 23));
- LoadImageCursor(ui::kCursorGrab, IDR_AURA_CURSOR_GRAB,
- gfx::Point(8, 5), gfx::Point(16, 10));
- LoadImageCursor(ui::kCursorGrabbing, IDR_AURA_CURSOR_GRABBING,
- gfx::Point(9, 9), gfx::Point(18, 18));
- LoadAnimatedCursor(ui::kCursorWait, IDR_THROBBER, 7, 7);
- LoadAnimatedCursor(ui::kCursorProgress, IDR_THROBBER, 7, 7);
- }
-
- ~ImageCursors() {
- UnloadAll();
- }
-
- void UnloadAll() {
- for (std::map<int, Cursor>::const_iterator it = cursors_.begin();
- it != cursors_.end(); ++it)
- ui::UnrefCustomXCursor(it->second);
-
- // Free animated cursors and images.
- for (AnimatedCursorMap::iterator it = animated_cursors_.begin();
- it != animated_cursors_.end(); ++it) {
- XcursorImagesDestroy(it->second.second); // also frees individual frames.
- XFreeCursor(ui::GetXDisplay(), it->second.first);
- }
- }
-
- // Returns true if we have an image resource loaded for the |native_cursor|.
- bool IsImageCursor(gfx::NativeCursor native_cursor) {
- int type = native_cursor.native_type();
- return cursors_.find(type) != cursors_.end() ||
- animated_cursors_.find(type) != animated_cursors_.end();
- }
-
- // Gets the X Cursor corresponding to the |native_cursor|.
- ::Cursor ImageCursorFromNative(gfx::NativeCursor native_cursor) {
- int type = native_cursor.native_type();
- if (animated_cursors_.find(type) != animated_cursors_.end())
- return animated_cursors_[type].first;
- DCHECK(cursors_.find(type) != cursors_.end());
- return cursors_[type];
- }
-
- private:
- // Creates an X Cursor from an image resource and puts it in the cursor map.
- void LoadImageCursor(int id,
- int resource_id,
- const gfx::Point& hot_1x,
- const gfx::Point& hot_2x) {
- const gfx::ImageSkia* image =
- ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
- const gfx::ImageSkiaRep& image_rep = image->GetRepresentation(
- ui::GetScaleFactorFromScale(scale_factor_));
- const gfx::Point& hot = (scale_factor_ == 1) ? hot_1x : hot_2x;
- XcursorImage* x_image =
- ui::SkBitmapToXcursorImage(&image_rep.sk_bitmap(), hot);
- cursors_[id] = ui::CreateReffedCustomXCursor(x_image);
- // |bitmap| is owned by the resource bundle. So we do not need to free it.
- }
-
- // Creates an animated X Cursor from an image resource and puts it in the
- // cursor map. The image is assumed to be a concatenation of animation frames.
- // Also, each frame is assumed to be square (width == height)
- void LoadAnimatedCursor(int id, int resource_id, int hot_x, int hot_y) {
- const gfx::ImageSkia* image =
- ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
- const gfx::ImageSkiaRep& image_rep = image->GetRepresentation(
- ui::GetScaleFactorFromScale(scale_factor_));
- const SkBitmap bitmap = image_rep.sk_bitmap();
- DCHECK_EQ(bitmap.config(), SkBitmap::kARGB_8888_Config);
- int frame_width = bitmap.height();
- int frame_height = frame_width;
- int total_width = bitmap.width();
- DCHECK_EQ(total_width % frame_width, 0);
- int frame_count = total_width / frame_width;
- DCHECK_GT(frame_count, 0);
- XcursorImages* x_images = XcursorImagesCreate(frame_count);
- x_images->nimage = frame_count;
- bitmap.lockPixels();
- unsigned int* pixels = bitmap.getAddr32(0, 0);
- // Create each frame.
- for (int i = 0; i < frame_count; ++i) {
- XcursorImage* x_image = XcursorImageCreate(frame_width, frame_height);
- for (int j = 0; j < frame_height; ++j) {
- // Copy j'th row of i'th frame.
- memcpy(x_image->pixels + j * frame_width,
- pixels + i * frame_width + j * total_width,
- frame_width * 4);
- }
- x_image->xhot = hot_x * scale_factor_;
- x_image->yhot = hot_y * scale_factor_;
- x_image->delay = kAnimatedCursorFrameDelayMs;
- x_images->images[i] = x_image;
- }
- bitmap.unlockPixels();
-
- animated_cursors_[id] = std::make_pair(
- XcursorImagesLoadCursor(ui::GetXDisplay(), x_images), x_images);
- // |bitmap| is owned by the resource bundle. So we do not need to free it.
- }
-
- // A map to hold all image cursors. It maps the cursor ID to the X Cursor.
- std::map<int, Cursor> cursors_;
-
- // A map to hold all animated cursors. It maps the cursor ID to the pair of
- // the X Cursor and the corresponding XcursorImages. We need a pointer to the
- // images so that we can free them on destruction.
- typedef std::map<int, std::pair<Cursor, XcursorImages*> > AnimatedCursorMap;
- AnimatedCursorMap animated_cursors_;
-
- float scale_factor_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageCursors);
-};
-
RootWindowHostLinux::RootWindowHostLinux(RootWindowHostDelegate* delegate,
const gfx::Rect& bounds)
: delegate_(delegate),
@@ -560,7 +292,6 @@ RootWindowHostLinux::RootWindowHostLinux(RootWindowHostDelegate* delegate,
bounds_(bounds),
focus_when_shown_(false),
pointer_barriers_(NULL),
- image_cursors_(new ImageCursors),
atom_cache_(xdisplay_, kAtomsToCache) {
XSetWindowAttributes swa;
memset(&swa, 0, sizeof(swa));
@@ -598,18 +329,7 @@ RootWindowHostLinux::RootWindowHostLinux(RootWindowHostDelegate* delegate,
XGetWindowAttributes(xdisplay_, x_root_window_, &attrs);
x_root_bounds_.SetRect(attrs.x, attrs.y, attrs.width, attrs.height);
- // Initialize invisible cursor.
- char nodata[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
- XColor black;
- black.red = black.green = black.blue = 0;
- Pixmap blank = XCreateBitmapFromData(xdisplay_, xwindow_,
- nodata, 8, 8);
- invisible_cursor_ = XCreatePixmapCursor(xdisplay_, blank, blank,
- &black, &black, 0, 0);
- XFreePixmap(xdisplay_, blank);
-
- if (RootWindow::hide_host_cursor())
- XDefineCursor(xdisplay_, x_root_window_, invisible_cursor_);
+ invisible_cursor_ = ui::CreateInvisibleCursor();
// TODO(erg): We currently only request window deletion events. We also
// should listen for activation events and anything else that GTK+ listens
@@ -652,9 +372,6 @@ RootWindowHostLinux::~RootWindowHostLinux() {
XDestroyWindow(xdisplay_, xwindow_);
- // Clears XCursorCache.
- ui::GetXCursor(ui::kCursorClearXCursorCache);
-
XFreeCursor(xdisplay_, invisible_cursor_);
}
@@ -664,6 +381,11 @@ bool RootWindowHostLinux::Dispatch(const base::NativeEvent& event) {
CheckXEventForConsistency(xev);
switch (xev->type) {
+ case EnterNotify: {
+ ui::MouseEvent mouseenter_event(xev);
+ delegate_->OnHostMouseEvent(&mouseenter_event);
+ break;
+ }
case Expose:
delegate_->AsRootWindow()->ScheduleFullDraw();
break;
@@ -915,9 +637,6 @@ gfx::AcceleratedWidget RootWindowHostLinux::GetAcceleratedWidget() {
}
void RootWindowHostLinux::Show() {
- // The device scale factor is now accessible, so load cursors now.
- image_cursors_->Reload(delegate_->GetDeviceScaleFactor());
-
if (!window_mapped_) {
// Before we map the window, set size hints. Otherwise, some window managers
// will ignore toplevel XMoveWindow commands.
@@ -1006,7 +725,7 @@ void RootWindowHostLinux::ShowCursor(bool show) {
if (show == cursor_shown_)
return;
cursor_shown_ = show;
- SetCursorInternal(show ? current_cursor_ : ui::kCursorNone);
+ SetCursorInternal(show ? current_cursor_ : invisible_cursor_);
}
bool RootWindowHostLinux::QueryMouseLocation(gfx::Point* location_return) {
@@ -1173,7 +892,6 @@ void RootWindowHostLinux::PostNativeEvent(
void RootWindowHostLinux::OnDeviceScaleFactorChanged(
float device_scale_factor) {
- image_cursors_->Reload(device_scale_factor);
}
void RootWindowHostLinux::PrepareForShutdown() {
@@ -1188,22 +906,7 @@ bool RootWindowHostLinux::IsWindowManagerPresent() {
}
void RootWindowHostLinux::SetCursorInternal(gfx::NativeCursor cursor) {
- // At times the cursor on the RootWindow is set before it is displayed. So
- // make sure the image-cursors are initialized properly before setting it.
- image_cursors_->Reload(delegate_->GetDeviceScaleFactor());
-
- ::Cursor xcursor;
- if (image_cursors_->IsImageCursor(cursor))
- xcursor = image_cursors_->ImageCursorFromNative(cursor);
- else if (cursor == ui::kCursorNone)
- xcursor = invisible_cursor_;
- else if (cursor == ui::kCursorCustom)
- xcursor = cursor.platform();
- else if (delegate_->GetDeviceScaleFactor() == 1.0)
- xcursor = ui::GetXCursor(CursorShapeFromNative(cursor));
- else
- xcursor = image_cursors_->ImageCursorFromNative(ui::kCursorPointer);
- XDefineCursor(xdisplay_, xwindow_, xcursor);
+ XDefineCursor(xdisplay_, xwindow_, cursor.platform());
}
// static
diff --git a/ui/aura/root_window_host_linux.h b/ui/aura/root_window_host_linux.h
index 86c6ae4..18e88c0 100644
--- a/ui/aura/root_window_host_linux.h
+++ b/ui/aura/root_window_host_linux.h
@@ -101,9 +101,6 @@ class RootWindowHostLinux : public RootWindowHost,
scoped_ptr<ui::ViewProp> prop_;
- class ImageCursors;
- scoped_ptr<ImageCursors> image_cursors_;
-
X11AtomCache atom_cache_;
DISALLOW_COPY_AND_ASSIGN(RootWindowHostLinux);
diff --git a/ui/aura/root_window_host_win.cc b/ui/aura/root_window_host_win.cc
index a4b2e2d..11f0aee 100644
--- a/ui/aura/root_window_host_win.cc
+++ b/ui/aura/root_window_host_win.cc
@@ -24,6 +24,7 @@ namespace {
const char* kRootWindowHostWinKey = "__AURA_ROOT_WINDOW_HOST_WIN__";
+// TODO(mazda): Move the cursor code to ui/base/cursor/cursor_loader_win.{cc,h}.
const wchar_t* GetCursorId(gfx::NativeCursor native_cursor) {
switch (native_cursor.native_type()) {
case ui::kCursorNull:
diff --git a/ui/aura/shared/compound_event_filter.cc b/ui/aura/shared/compound_event_filter.cc
index 6ddda9b..7e14cf7 100644
--- a/ui/aura/shared/compound_event_filter.cc
+++ b/ui/aura/shared/compound_event_filter.cc
@@ -6,6 +6,7 @@
#include "ui/aura/client/activation_client.h"
#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/env.h"
#include "ui/aura/focus_manager.h"
#include "ui/aura/root_window.h"
@@ -86,9 +87,17 @@ size_t CompoundEventFilter::GetFilterCount() const {
// CompoundEventFilter, private:
void CompoundEventFilter::UpdateCursor(Window* target, ui::MouseEvent* event) {
- client::CursorClient* client =
- client::GetCursorClient(target->GetRootWindow());
- if (client) {
+ // If drag and drop is in progress, let the drag drop client set the cursor
+ // instead of setting the cursor here.
+ aura::RootWindow* root_window = target->GetRootWindow();
+ client::DragDropClient* drag_drop_client =
+ client::GetDragDropClient(root_window);
+ if (drag_drop_client && drag_drop_client->IsDragDropInProgress())
+ return;
+
+ client::CursorClient* cursor_client =
+ client::GetCursorClient(root_window);
+ if (cursor_client) {
gfx::NativeCursor cursor = target->GetCursor(event->location());
if (event->flags() & ui::EF_IS_NON_CLIENT) {
int window_component =
@@ -96,7 +105,9 @@ void CompoundEventFilter::UpdateCursor(Window* target, ui::MouseEvent* event) {
cursor = CursorForWindowComponent(window_component);
}
- client->SetCursor(cursor);
+ cursor_client->SetCursor(cursor);
+ cursor_client->SetDeviceScaleFactor(
+ root_window->AsRootWindowHostDelegate()->GetDeviceScaleFactor());
}
}
@@ -181,7 +192,11 @@ ui::EventResult CompoundEventFilter::OnMouseEvent(ui::MouseEvent* event) {
// It should also update the cursor for clicking and wheels for ChromeOS boot.
// When ChromeOS is booted, it hides the mouse cursor but immediate mouse
// operation will show the cursor.
- if (event->type() == ui::ET_MOUSE_MOVED ||
+ // We also update the cursor for mouse enter in case a mouse cursor is sent to
+ // outside of the root window and moved back for some reasons (e.g. running on
+ // on Desktop for testing, or a bug in pointer barrier).
+ if (event->type() == ui::ET_MOUSE_ENTERED ||
+ event->type() == ui::ET_MOUSE_MOVED ||
event->type() == ui::ET_MOUSE_PRESSED ||
event->type() == ui::ET_MOUSEWHEEL) {
SetCursorVisibilityOnEvent(window, event, true);
diff --git a/ui/aura/shared/compound_event_filter_unittest.cc b/ui/aura/shared/compound_event_filter_unittest.cc
index a74591c..4a7bad2 100644
--- a/ui/aura/shared/compound_event_filter_unittest.cc
+++ b/ui/aura/shared/compound_event_filter_unittest.cc
@@ -37,6 +37,9 @@ class TestVisibleClient : public aura::client::CursorClient {
return visible_;
}
+ virtual void SetDeviceScaleFactor(float scale_factor) OVERRIDE {
+ }
+
private:
bool visible_;
};
diff --git a/ui/base/cursor/cursor.cc b/ui/base/cursor/cursor.cc
index e2811bf..223042e 100644
--- a/ui/base/cursor/cursor.cc
+++ b/ui/base/cursor/cursor.cc
@@ -8,17 +8,20 @@ namespace ui {
Cursor::Cursor()
: native_type_(0),
- platform_cursor_(0) {
+ platform_cursor_(0),
+ device_scale_factor_(0.0f) {
}
Cursor::Cursor(int type)
: native_type_(type),
- platform_cursor_(0) {
+ platform_cursor_(0),
+ device_scale_factor_(0.0f) {
}
Cursor::Cursor(const Cursor& cursor)
: native_type_(cursor.native_type_),
- platform_cursor_(cursor.platform_cursor_) {
+ platform_cursor_(cursor.platform_cursor_),
+ device_scale_factor_(cursor.device_scale_factor_) {
if (native_type_ == kCursorCustom)
RefCustomCursor();
}
@@ -29,22 +32,23 @@ Cursor::~Cursor() {
}
void Cursor::SetPlatformCursor(const PlatformCursor& platform) {
- if (platform_cursor_)
+ if (native_type_ == kCursorCustom)
UnrefCustomCursor();
- native_type_ = kCursorCustom;
platform_cursor_ = platform;
- RefCustomCursor();
+ if (native_type_ == kCursorCustom)
+ RefCustomCursor();
}
void Cursor::Assign(const Cursor& cursor) {
if (*this == cursor)
return;
native_type_ = cursor.native_type_;
- if (platform_cursor_)
+ if (native_type_ == kCursorCustom)
UnrefCustomCursor();
platform_cursor_ = cursor.platform_cursor_;
- if (platform_cursor_)
+ if (native_type_ == kCursorCustom)
RefCustomCursor();
+ device_scale_factor_ = cursor.device_scale_factor_;
}
} // namespace ui
diff --git a/ui/base/cursor/cursor.h b/ui/base/cursor/cursor.h
index 2383274..43c201d 100644
--- a/ui/base/cursor/cursor.h
+++ b/ui/base/cursor/cursor.h
@@ -102,16 +102,24 @@ class UI_EXPORT Cursor {
int native_type() const { return native_type_; }
PlatformCursor platform() const { return platform_cursor_; }
+ float device_scale_factor() const {
+ return device_scale_factor_;
+ }
+ void set_device_scale_factor(float device_scale_factor) {
+ device_scale_factor_ = device_scale_factor;
+ }
bool operator==(int type) const { return native_type_ == type; }
bool operator==(const Cursor& cursor) const {
return native_type_ == cursor.native_type_ &&
- platform_cursor_ == cursor.platform_cursor_;
+ platform_cursor_ == cursor.platform_cursor_ &&
+ device_scale_factor_ == cursor.device_scale_factor_;
}
bool operator!=(int type) const { return native_type_ != type; }
bool operator!=(const Cursor& cursor) const {
return native_type_ != cursor.native_type_ ||
- platform_cursor_ != cursor.platform_cursor_;
+ platform_cursor_ != cursor.platform_cursor_ ||
+ device_scale_factor_ != cursor.device_scale_factor_;
}
void operator=(const Cursor& cursor) {
@@ -125,6 +133,9 @@ class UI_EXPORT Cursor {
int native_type_;
PlatformCursor platform_cursor_;
+
+ // The device scale factor for the cursor.
+ float device_scale_factor_;
};
} // namespace ui
diff --git a/ui/base/cursor/cursor_loader.h b/ui/base/cursor/cursor_loader.h
new file mode 100644
index 0000000..48167e7
--- /dev/null
+++ b/ui/base/cursor/cursor_loader.h
@@ -0,0 +1,61 @@
+// 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 UI_BASE_CURSOR_CURSOR_LOADER_H_
+#define UI_BASE_CURSOR_CURSOR_LOADER_H_
+
+#include "base/logging.h"
+#include "ui/base/ui_export.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/point.h"
+
+namespace ui {
+
+class UI_EXPORT CursorLoader {
+ public:
+ CursorLoader() : device_scale_factor_(0.0f) {}
+ virtual ~CursorLoader() {}
+
+ // Returns the device scale factor used by the loader.
+ float device_scale_factor() const {
+ return device_scale_factor_;
+ }
+
+ // Sets the device scale factor used by the loader.
+ void set_device_scale_factor(float device_scale_factor) {
+ device_scale_factor_ = device_scale_factor;
+ }
+
+ // Creates a cursor from an image resource and puts it in the cursor map.
+ virtual void LoadImageCursor(int id,
+ int resource_id,
+ const gfx::Point& hot) = 0;
+
+ // Creates an animated cursor from an image resource and puts it in the
+ // cursor map. The image is assumed to be a concatenation of animation frames
+ // from left to right. Also, each frame is assumed to be square
+ // (width == height).
+ // |frame_delay_ms| is the delay between frames in millisecond.
+ virtual void LoadAnimatedCursor(int id,
+ int resource_id,
+ const gfx::Point& hot,
+ int frame_delay_ms) = 0;
+
+ // Unloads all the cursors.
+ virtual void UnloadAll() = 0;
+
+ // Sets the platform cursor based on the native type of |cursor|.
+ virtual void SetPlatformCursor(gfx::NativeCursor* cursor) = 0;
+
+ // Creates a CursorLoader.
+ static CursorLoader* Create();
+
+ private:
+ // The device scale factor used by the loader.
+ float device_scale_factor_;
+};
+
+} // namespace ui
+
+#endif // UI_BASE_CURSOR_CURSOR_LOADER_H_
diff --git a/ui/base/cursor/cursor_loader_win.cc b/ui/base/cursor/cursor_loader_win.cc
new file mode 100644
index 0000000..8fc9adc
--- /dev/null
+++ b/ui/base/cursor/cursor_loader_win.cc
@@ -0,0 +1,40 @@
+// 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 "ui/base/cursor/cursor_loader_win.h"
+
+namespace ui {
+
+CursorLoader* CursorLoader::Create() {
+ return new CursorLoaderWin;
+}
+
+CursorLoaderWin::CursorLoaderWin() {
+}
+
+CursorLoaderWin::~CursorLoaderWin() {
+}
+
+void CursorLoaderWin::LoadImageCursor(int id,
+ int resource_id,
+ const gfx::Point& hot) {
+ // NOTIMPLEMENTED();
+}
+
+void CursorLoaderWin::LoadAnimatedCursor(int id,
+ int resource_id,
+ const gfx::Point& hot,
+ int frame_delay_ms) {
+ // NOTIMPLEMENTED();
+}
+
+void CursorLoaderWin::UnloadAll() {
+ // NOTIMPLEMENTED();
+}
+
+void CursorLoaderWin::SetPlatformCursor(gfx::NativeCursor* cursor) {
+ // NOTIMPLEMENTED();
+}
+
+} // namespace ui
diff --git a/ui/base/cursor/cursor_loader_win.h b/ui/base/cursor/cursor_loader_win.h
new file mode 100644
index 0000000..6447283
--- /dev/null
+++ b/ui/base/cursor/cursor_loader_win.h
@@ -0,0 +1,35 @@
+// 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 UI_BASE_CURSOR_CURSOR_LOADER_WIN_H_
+#define UI_BASE_CURSOR_CURSOR_LOADER_WIN_H_
+
+#include "base/compiler_specific.h"
+#include "ui/base/cursor/cursor_loader.h"
+
+namespace ui {
+
+class CursorLoaderWin : public CursorLoader {
+ public:
+ CursorLoaderWin();
+ virtual ~CursorLoaderWin();
+
+ // Overridden from CursorLoader:
+ virtual void LoadImageCursor(int id,
+ int resource_id,
+ const gfx::Point& hot) OVERRIDE;
+ virtual void LoadAnimatedCursor(int id,
+ int resource_id,
+ const gfx::Point& hot,
+ int frame_delay_ms) OVERRIDE;
+ virtual void UnloadAll() OVERRIDE;
+ virtual void SetPlatformCursor(gfx::NativeCursor* cursor) OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CursorLoaderWin);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_CURSOR_CURSOR_LOADER_WIN_H_
diff --git a/ui/base/cursor/cursor_loader_x11.cc b/ui/base/cursor/cursor_loader_x11.cc
new file mode 100644
index 0000000..dce19d4
--- /dev/null
+++ b/ui/base/cursor/cursor_loader_x11.cc
@@ -0,0 +1,203 @@
+// 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 "ui/base/cursor/cursor_loader_x11.h"
+
+#include <X11/Xlib.h>
+#include <X11/cursorfont.h>
+
+#include "base/logging.h"
+#include "grit/ui_resources.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_skia.h"
+
+namespace {
+
+// Returns X font cursor shape from an Aura cursor.
+int CursorShapeFromNative(gfx::NativeCursor native_cursor) {
+ switch (native_cursor.native_type()) {
+ case ui::kCursorMiddlePanning:
+ return XC_fleur;
+ case ui::kCursorEastPanning:
+ return XC_sb_right_arrow;
+ case ui::kCursorNorthPanning:
+ return XC_sb_up_arrow;
+ case ui::kCursorNorthEastPanning:
+ return XC_top_right_corner;
+ case ui::kCursorNorthWestPanning:
+ return XC_top_left_corner;
+ case ui::kCursorSouthPanning:
+ return XC_sb_down_arrow;
+ case ui::kCursorSouthEastPanning:
+ return XC_bottom_right_corner;
+ case ui::kCursorSouthWestPanning:
+ return XC_bottom_left_corner;
+ case ui::kCursorWestPanning:
+ return XC_sb_left_arrow;
+ case ui::kCursorNone:
+ case ui::kCursorGrab:
+ case ui::kCursorGrabbing:
+ // TODO(jamescook): Need cursors for these. crbug.com/111650
+ return XC_left_ptr;
+
+ case ui::kCursorNull:
+ case ui::kCursorPointer:
+ case ui::kCursorNoDrop:
+ case ui::kCursorNotAllowed:
+ case ui::kCursorCopy:
+ case ui::kCursorMove:
+ case ui::kCursorEastResize:
+ case ui::kCursorNorthResize:
+ case ui::kCursorSouthResize:
+ case ui::kCursorWestResize:
+ case ui::kCursorNorthEastResize:
+ case ui::kCursorNorthWestResize:
+ case ui::kCursorSouthWestResize:
+ case ui::kCursorSouthEastResize:
+ case ui::kCursorIBeam:
+ case ui::kCursorAlias:
+ case ui::kCursorCell:
+ case ui::kCursorContextMenu:
+ case ui::kCursorCross:
+ case ui::kCursorHelp:
+ case ui::kCursorWait:
+ case ui::kCursorNorthSouthResize:
+ case ui::kCursorEastWestResize:
+ case ui::kCursorNorthEastSouthWestResize:
+ case ui::kCursorNorthWestSouthEastResize:
+ case ui::kCursorProgress:
+ case ui::kCursorColumnResize:
+ case ui::kCursorRowResize:
+ case ui::kCursorVerticalText:
+ case ui::kCursorZoomIn:
+ case ui::kCursorZoomOut:
+ NOTREACHED() << "Cursor (" << native_cursor.native_type() << ") should "
+ << "have an image asset.";
+ return XC_left_ptr;
+ case ui::kCursorCustom:
+ NOTREACHED();
+ return XC_left_ptr;
+ }
+ NOTREACHED();
+ return XC_left_ptr;
+}
+
+} // namespace
+
+namespace ui {
+
+CursorLoader* CursorLoader::Create() {
+ return new CursorLoaderX11;
+}
+
+CursorLoaderX11::CursorLoaderX11() {
+}
+
+CursorLoaderX11::~CursorLoaderX11() {
+ UnloadAll();
+ // Clears XCursorCache.
+ ui::GetXCursor(ui::kCursorClearXCursorCache);
+}
+
+void CursorLoaderX11::LoadImageCursor(int id,
+ int resource_id,
+ const gfx::Point& hot) {
+ const gfx::ImageSkia* image =
+ ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
+ const gfx::ImageSkiaRep& image_rep = image->GetRepresentation(
+ ui::GetScaleFactorFromScale(device_scale_factor()));
+ XcursorImage* x_image =
+ ui::SkBitmapToXcursorImage(&image_rep.sk_bitmap(), hot);
+ cursors_[id] = ui::CreateReffedCustomXCursor(x_image);
+ // |image_rep| is owned by the resource bundle. So we do not need to free it.
+}
+
+void CursorLoaderX11::LoadAnimatedCursor(int id,
+ int resource_id,
+ const gfx::Point& hot,
+ int frame_delay_ms) {
+ const gfx::ImageSkia* image =
+ ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
+ const gfx::ImageSkiaRep& image_rep = image->GetRepresentation(
+ ui::GetScaleFactorFromScale(device_scale_factor()));
+ const SkBitmap bitmap = image_rep.sk_bitmap();
+ DCHECK_EQ(bitmap.config(), SkBitmap::kARGB_8888_Config);
+ int frame_width = bitmap.height();
+ int frame_height = frame_width;
+ int total_width = bitmap.width();
+ DCHECK_EQ(total_width % frame_width, 0);
+ int frame_count = total_width / frame_width;
+ DCHECK_GT(frame_count, 0);
+ XcursorImages* x_images = XcursorImagesCreate(frame_count);
+ x_images->nimage = frame_count;
+ bitmap.lockPixels();
+ unsigned int* pixels = bitmap.getAddr32(0, 0);
+ // Create each frame.
+ for (int frame = 0; frame < frame_count; ++frame) {
+ XcursorImage* x_image = XcursorImageCreate(frame_width, frame_height);
+ for (int row = 0; row < frame_height; ++row) {
+ // Copy |row|'th row of |frame|'th frame.
+ memcpy(x_image->pixels + row * frame_width,
+ pixels + frame * frame_width + row * total_width,
+ frame_width * 4);
+ }
+ x_image->xhot = hot.x();
+ x_image->yhot = hot.y();
+ x_image->delay = frame_delay_ms;
+ x_images->images[frame] = x_image;
+ }
+ bitmap.unlockPixels();
+
+ animated_cursors_[id] = std::make_pair(
+ XcursorImagesLoadCursor(ui::GetXDisplay(), x_images), x_images);
+ // |bitmap| is owned by the resource bundle. So we do not need to free it.
+}
+
+void CursorLoaderX11::UnloadAll() {
+ for (ImageCursorMap::const_iterator it = cursors_.begin();
+ it != cursors_.end(); ++it)
+ ui::UnrefCustomXCursor(it->second);
+
+ // Free animated cursors and images.
+ for (AnimatedCursorMap::iterator it = animated_cursors_.begin();
+ it != animated_cursors_.end(); ++it) {
+ XcursorImagesDestroy(it->second.second); // also frees individual frames.
+ XFreeCursor(ui::GetXDisplay(), it->second.first);
+ }
+}
+
+void CursorLoaderX11::SetPlatformCursor(gfx::NativeCursor* cursor) {
+ DCHECK(cursor);
+
+ ::Cursor xcursor;
+ if (IsImageCursor(*cursor))
+ xcursor = ImageCursorFromNative(*cursor);
+ else if (*cursor == ui::kCursorCustom)
+ xcursor = cursor->platform();
+ else if (device_scale_factor() == 1.0f)
+ xcursor = ui::GetXCursor(CursorShapeFromNative(*cursor));
+ else
+ xcursor = ImageCursorFromNative(ui::kCursorPointer);
+
+ cursor->SetPlatformCursor(xcursor);
+}
+
+bool CursorLoaderX11::IsImageCursor(gfx::NativeCursor native_cursor) {
+ int type = native_cursor.native_type();
+ return cursors_.count(type) || animated_cursors_.count(type);
+}
+
+::Cursor CursorLoaderX11::ImageCursorFromNative(
+ gfx::NativeCursor native_cursor) {
+ int type = native_cursor.native_type();
+ if (animated_cursors_.count(type))
+ return animated_cursors_[type].first;
+ DCHECK(cursors_.find(type) != cursors_.end());
+ return cursors_[type];
+}
+
+}
diff --git a/ui/base/cursor/cursor_loader_x11.h b/ui/base/cursor/cursor_loader_x11.h
new file mode 100644
index 0000000..32f0e1a
--- /dev/null
+++ b/ui/base/cursor/cursor_loader_x11.h
@@ -0,0 +1,58 @@
+// 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 UI_BASE_CURSOR_CURSOR_LOADER_X11_H_
+#define UI_BASE_CURSOR_CURSOR_LOADER_X11_H_
+
+#include <X11/Xcursor/Xcursor.h>
+#include <map>
+
+#include "base/compiler_specific.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/cursor/cursor_loader.h"
+
+namespace ui {
+
+class CursorLoaderX11 : public CursorLoader {
+ public:
+ CursorLoaderX11();
+ virtual ~CursorLoaderX11();
+
+ // Overridden from CursorLoader:
+ virtual void LoadImageCursor(int id,
+ int resource_id,
+ const gfx::Point& hot) OVERRIDE;
+ virtual void LoadAnimatedCursor(int id,
+ int resource_id,
+ const gfx::Point& hot,
+ int frame_delay_ms) OVERRIDE;
+ virtual void UnloadAll() OVERRIDE;
+ virtual void SetPlatformCursor(gfx::NativeCursor* cursor) OVERRIDE;
+
+ private:
+ // Returns true if we have an image resource loaded for the |native_cursor|.
+ bool IsImageCursor(gfx::NativeCursor native_cursor);
+
+ // Gets the X Cursor corresponding to the |native_cursor|.
+ ::Cursor ImageCursorFromNative(gfx::NativeCursor native_cursor);
+
+ // A map to hold all image cursors. It maps the cursor ID to the X Cursor.
+ typedef std::map<int, ::Cursor> ImageCursorMap;
+ ImageCursorMap cursors_;
+
+ // A map to hold all animated cursors. It maps the cursor ID to the pair of
+ // the X Cursor and the corresponding XcursorImages. We need a pointer to the
+ // images so that we can free them on destruction.
+ typedef std::map<int, std::pair< ::Cursor, XcursorImages*> >
+ AnimatedCursorMap;
+ AnimatedCursorMap animated_cursors_;
+
+ ::Cursor invisible_cursor_;
+
+ DISALLOW_COPY_AND_ASSIGN(CursorLoaderX11);
+};
+
+} // namespace ui
+
+#endif // UI_BASE_CURSOR_CURSOR_LOADER_X11_H_
diff --git a/ui/base/x/events_x.cc b/ui/base/x/events_x.cc
index dff3298..1dd3a66 100644
--- a/ui/base/x/events_x.cc
+++ b/ui/base/x/events_x.cc
@@ -775,6 +775,10 @@ base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) {
case MotionNotify:
return base::TimeDelta::FromMilliseconds(native_event->xmotion.time);
break;
+ case EnterNotify:
+ case LeaveNotify:
+ return base::TimeDelta::FromMilliseconds(native_event->xcrossing.time);
+ break;
case GenericEvent: {
double start, end;
if (GetGestureTimes(native_event, &start, &end)) {
diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc
index efe05af..05f50ec 100644
--- a/ui/base/x/x11_util.cc
+++ b/ui/base/x/x11_util.cc
@@ -453,6 +453,28 @@ XcursorImage* SkBitmapToXcursorImage(const SkBitmap* bitmap,
}
#endif
+void HideHostCursor() {
+ CR_DEFINE_STATIC_LOCAL(XScopedCursor, invisible_cursor,
+ (CreateInvisibleCursor(), ui::GetXDisplay()));
+ XDefineCursor(ui::GetXDisplay(), DefaultRootWindow(ui::GetXDisplay()),
+ invisible_cursor.get());
+}
+
+::Cursor CreateInvisibleCursor() {
+ Display* xdisplay = ui::GetXDisplay();
+ ::Cursor invisible_cursor;
+ char nodata[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ XColor black;
+ black.red = black.green = black.blue = 0;
+ Pixmap blank = XCreateBitmapFromData(xdisplay,
+ DefaultRootWindow(xdisplay),
+ nodata, 8, 8);
+ invisible_cursor = XCreatePixmapCursor(xdisplay, blank, blank,
+ &black, &black, 0, 0);
+ XFreePixmap(xdisplay, blank);
+ return invisible_cursor;
+}
+
XID GetX11RootWindow() {
return DefaultRootWindow(GetXDisplay());
}
@@ -1352,6 +1374,25 @@ XScopedString::~XScopedString() {
XFree(string_);
}
+XScopedCursor::XScopedCursor(::Cursor cursor, Display* display)
+ : cursor_(cursor),
+ display_(display) {
+}
+
+XScopedCursor::~XScopedCursor() {
+ reset(0U);
+}
+
+::Cursor XScopedCursor::get() const {
+ return cursor_;
+}
+
+void XScopedCursor::reset(::Cursor cursor) {
+ if (cursor_)
+ XFreeCursor(display_, cursor_);
+ cursor_ = cursor;
+}
+
// ----------------------------------------------------------------------------
// These functions are declared in x11_util_internal.h because they require
// XLib.h to be included, and it conflicts with many other headers.
diff --git a/ui/base/x/x11_util.h b/ui/base/x/x11_util.h
index 869ef7c..d6dc0c3 100644
--- a/ui/base/x/x11_util.h
+++ b/ui/base/x/x11_util.h
@@ -97,6 +97,12 @@ UI_EXPORT XcursorImage* SkBitmapToXcursorImage(const SkBitmap* bitmap,
const gfx::Point& hotspot);
#endif
+// Hides the host cursor.
+UI_EXPORT void HideHostCursor();
+
+// Returns an invisible cursor.
+UI_EXPORT ::Cursor CreateInvisibleCursor();
+
// These functions do not cache their results --------------------------
// Get the X window id for the default root window
@@ -319,6 +325,24 @@ class UI_EXPORT XScopedString {
DISALLOW_COPY_AND_ASSIGN(XScopedString);
};
+// Keeps track of a cursor returned by an X function and makes sure it's
+// XFreeCursor'd.
+class UI_EXPORT XScopedCursor {
+ public:
+ // Keeps track of |cursor| created with |display|.
+ XScopedCursor(::Cursor cursor, Display* display);
+ ~XScopedCursor();
+
+ ::Cursor get() const;
+ void reset(::Cursor cursor);
+
+ private:
+ ::Cursor cursor_;
+ Display* display_;
+
+ DISALLOW_COPY_AND_ASSIGN(XScopedCursor);
+};
+
} // namespace ui
#endif // UI_BASE_X_X11_UTIL_H_
diff --git a/ui/ui.gyp b/ui/ui.gyp
index 03dd20a..b0b418f 100644
--- a/ui/ui.gyp
+++ b/ui/ui.gyp
@@ -137,6 +137,11 @@
'base/cocoa/window_size_constants.mm',
'base/cursor/cursor.cc',
'base/cursor/cursor.h',
+ 'base/cursor/cursor_loader.h',
+ 'base/cursor/cursor_loader_win.cc',
+ 'base/cursor/cursor_loader_win.h',
+ 'base/cursor/cursor_loader_x11.cc',
+ 'base/cursor/cursor_loader_x11.h',
'base/cursor/cursor_win.cc',
'base/cursor/cursor_x11.cc',
'base/dialogs/base_shell_dialog.cc',
@@ -542,6 +547,8 @@
'sources!': [
'base/cursor/cursor.cc',
'base/cursor/cursor.h',
+ 'base/cursor/cursor_loader_x11.cc',
+ 'base/cursor/cursor_loader_x11.h',
'base/cursor/cursor_win.cc',
'base/cursor/cursor_x11.cc',
'base/native_theme/native_theme_aura.cc',
diff --git a/webkit/glue/webcursor_aura.cc b/webkit/glue/webcursor_aura.cc
index 2642c47..4510e96f 100644
--- a/webkit/glue/webcursor_aura.cc
+++ b/webkit/glue/webcursor_aura.cc
@@ -99,7 +99,7 @@ gfx::NativeCursor WebCursor::GetNativeCursor() {
case WebCursorInfo::TypeGrabbing:
return ui::kCursorGrabbing;
case WebCursorInfo::TypeCustom: {
- ui::Cursor cursor;
+ ui::Cursor cursor(ui::kCursorCustom);
cursor.SetPlatformCursor(GetPlatformCursor());
return cursor;
}