Index: ui/base/cursor/cursor_loader_x11.cc |
diff --git a/ui/base/cursor/cursor_loader_x11.cc b/ui/base/cursor/cursor_loader_x11.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..dce19d426c4e01a3d8cd33b88c4a8ed02a3684f7 |
--- /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]; |
+} |
+ |
+} |