diff options
author | mazda@chromium.org <mazda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-11 20:18:35 +0000 |
---|---|---|
committer | mazda@chromium.org <mazda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-11 20:18:35 +0000 |
commit | 151ffdff429adc13dea9afbe18602745981a9dcc (patch) | |
tree | 65ea7ff184d3e543d2a6213e29a96119eed4081b /ui/base | |
parent | 843fe4276bb2a001d6bdbb74dda7ef44a707cec7 (diff) | |
download | chromium_src-151ffdff429adc13dea9afbe18602745981a9dcc.zip chromium_src-151ffdff429adc13dea9afbe18602745981a9dcc.tar.gz chromium_src-151ffdff429adc13dea9afbe18602745981a9dcc.tar.bz2 |
Move ash specific cursor code to CursorManager.
Main changes are as follows.
- Move the responsibility of managing cursors to ash::CursorManager from aura::RootWindowHostLinux.
- Set the same cursor to all root windows with CursorManager so that cursor is updated properly while dragging across displays
- Introduce CursorLoader class, which implements platform specific cursor loading.
- Add SetDeviceScaleFactor to CursorClient, which sets the device scale factor used for the cursor.
BUG=132862,144756
Review URL: https://chromiumcodereview.appspot.com/10919135
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@156109 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/base')
-rw-r--r-- | ui/base/cursor/cursor.cc | 20 | ||||
-rw-r--r-- | ui/base/cursor/cursor.h | 15 | ||||
-rw-r--r-- | ui/base/cursor/cursor_loader.h | 61 | ||||
-rw-r--r-- | ui/base/cursor/cursor_loader_win.cc | 40 | ||||
-rw-r--r-- | ui/base/cursor/cursor_loader_win.h | 35 | ||||
-rw-r--r-- | ui/base/cursor/cursor_loader_x11.cc | 203 | ||||
-rw-r--r-- | ui/base/cursor/cursor_loader_x11.h | 58 | ||||
-rw-r--r-- | ui/base/x/events_x.cc | 4 | ||||
-rw-r--r-- | ui/base/x/x11_util.cc | 41 | ||||
-rw-r--r-- | ui/base/x/x11_util.h | 24 |
10 files changed, 491 insertions, 10 deletions
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_ |