| 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];
|
| +}
|
| +
|
| +}
|
|
|