Skip to content

Commit

Permalink
Add cursor support to Ozone X11.
Browse files Browse the repository at this point in the history
This CL adds a CursorFactoryOzone implementation for Ozone X11. A
X11CursorOzone class is added along with X11WindowOzone. This class
exists to own the X11 cursor id and own associated resources. It
cleans up X resources on destruction.

BUG=361137

Review URL: https://codereview.chromium.org/1664373002

Cr-Commit-Position: refs/heads/master@{#376735}
  • Loading branch information
kylechar authored and Commit bot committed Feb 22, 2016
1 parent d4df77d commit d642dcb
Show file tree
Hide file tree
Showing 12 changed files with 303 additions and 8 deletions.
2 changes: 1 addition & 1 deletion ash/extended_desktop_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ TEST_F(ExtendedDesktopTest, TestCursor) {
aura::WindowTreeHost* host0 = root_windows[0]->GetHost();
aura::WindowTreeHost* host1 = root_windows[1]->GetHost();
EXPECT_EQ(ui::kCursorPointer, host0->last_cursor().native_type());
EXPECT_EQ(ui::kCursorPointer, host1->last_cursor().native_type());
EXPECT_EQ(ui::kCursorNull, host1->last_cursor().native_type());
Shell::GetInstance()->cursor_manager()->SetCursor(ui::kCursorCopy);
EXPECT_EQ(ui::kCursorCopy, host0->last_cursor().native_type());
EXPECT_EQ(ui::kCursorCopy, host1->last_cursor().native_type());
Expand Down
1 change: 0 additions & 1 deletion ash/root_window_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,6 @@ void RootWindowController::Init(RootWindowType root_window_type,
Shell* shell = Shell::GetInstance();
shell->InitRootWindow(root_window);

ash_host_->AsWindowTreeHost()->SetCursor(ui::kCursorPointer);
CreateContainersInRootWindow(root_window);

CreateSystemBackground(first_run_after_boot);
Expand Down
5 changes: 3 additions & 2 deletions ui/base/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import("//build/config/compiler/compiler.gni")
import("//build/config/sanitizers/sanitizers.gni")
import("//build/config/ui.gni")
import("//testing/test.gni")
import("//ui/ozone/ozone.gni")

if (is_android) {
import("//build/config/android/config.gni")
Expand Down Expand Up @@ -397,7 +398,7 @@ component("base") {
"dragdrop/drag_utils_aura.cc",
]
}
if (use_x11) {
if (use_x11 || ozone_platform_x11) {
sources += [
"x/x11_foreign_window_manager.cc",
"x/x11_foreign_window_manager.h",
Expand Down Expand Up @@ -505,7 +506,7 @@ component("base") {
]
}

if (use_x11) {
if (use_x11 || ozone_platform_x11) {
#'all_dependent_settings': {
#'ldflags': [
#'-L<(PRODUCT_DIR)',
Expand Down
2 changes: 2 additions & 0 deletions ui/ozone/platform/x11/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ source_set("x11") {
"client_native_pixmap_factory_x11.h",
"ozone_platform_x11.cc",
"ozone_platform_x11.h",
"x11_cursor_factory_ozone.cc",
"x11_cursor_factory_ozone.h",
"x11_surface_factory.cc",
"x11_surface_factory.h",
]
Expand Down
6 changes: 3 additions & 3 deletions ui/ozone/platform/x11/ozone_platform_x11.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
#include <utility>

#include "base/memory/scoped_ptr.h"
#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
#include "ui/events/platform/x11/x11_event_source_libevent.h"
#include "ui/ozone/common/native_display_delegate_ozone.h"
#include "ui/ozone/common/stub_overlay_manager.h"
#include "ui/ozone/platform/x11/x11_cursor_factory_ozone.h"
#include "ui/ozone/platform/x11/x11_surface_factory.h"
#include "ui/ozone/public/gpu_platform_support.h"
#include "ui/ozone/public/gpu_platform_support_host.h"
Expand Down Expand Up @@ -82,7 +82,7 @@ class OzonePlatformX11 : public OzonePlatform {
surface_factory_ozone_.reset(new X11SurfaceFactory());
overlay_manager_.reset(new StubOverlayManager());
input_controller_ = CreateStubInputController();
cursor_factory_ozone_.reset(new BitmapCursorFactoryOzone);
cursor_factory_ozone_.reset(new X11CursorFactoryOzone());
gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost());
}

Expand All @@ -96,7 +96,7 @@ class OzonePlatformX11 : public OzonePlatform {
scoped_ptr<X11EventSourceLibevent> event_source_;
scoped_ptr<OverlayManagerOzone> overlay_manager_;
scoped_ptr<InputController> input_controller_;
scoped_ptr<BitmapCursorFactoryOzone> cursor_factory_ozone_;
scoped_ptr<X11CursorFactoryOzone> cursor_factory_ozone_;
scoped_ptr<GpuPlatformSupportHost> gpu_platform_support_host_;

// Objects in the GPU process.
Expand Down
100 changes: 100 additions & 0 deletions ui/ozone/platform/x11/x11_cursor_factory_ozone.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright 2016 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/ozone/platform/x11/x11_cursor_factory_ozone.h"

#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/cursor/cursors_aura.h"
#include "ui/gfx/geometry/point.h"

namespace ui {

namespace {

X11CursorOzone* ToX11CursorOzone(PlatformCursor cursor) {
return static_cast<X11CursorOzone*>(cursor);
}

PlatformCursor ToPlatformCursor(X11CursorOzone* cursor) {
return static_cast<PlatformCursor>(cursor);
}

// Gets default aura cursor bitmap/hotspot and creates a X11CursorOzone with it.
scoped_refptr<X11CursorOzone> CreateAuraX11Cursor(int type) {
SkBitmap bitmap;
gfx::Point hotspot;
if (GetCursorBitmap(type, &bitmap, &hotspot)) {
return new X11CursorOzone(bitmap, hotspot);
}
return nullptr;
}

} // namespace

X11CursorFactoryOzone::X11CursorFactoryOzone()
: invisible_cursor_(X11CursorOzone::CreateInvisible()) {}

X11CursorFactoryOzone::~X11CursorFactoryOzone() {}

PlatformCursor X11CursorFactoryOzone::GetDefaultCursor(int type) {
return ToPlatformCursor(GetDefaultCursorInternal(type).get());
}

PlatformCursor X11CursorFactoryOzone::CreateImageCursor(
const SkBitmap& bitmap,
const gfx::Point& hotspot) {
// There is a problem with custom cursors that have no custom data. The
// resulting SkBitmap is empty and X crashes when creating a zero size cursor
// image. Return invisible cursor here instead.
if (bitmap.drawsNothing()) {
return ToPlatformCursor(invisible_cursor_.get());
}

X11CursorOzone* cursor = new X11CursorOzone(bitmap, hotspot);
cursor->AddRef();
return ToPlatformCursor(cursor);
}

PlatformCursor X11CursorFactoryOzone::CreateAnimatedCursor(
const std::vector<SkBitmap>& bitmaps,
const gfx::Point& hotspot,
int frame_delay_ms) {
X11CursorOzone* cursor = new X11CursorOzone(bitmaps, hotspot, frame_delay_ms);
cursor->AddRef();
return ToPlatformCursor(cursor);
}

void X11CursorFactoryOzone::RefImageCursor(PlatformCursor cursor) {
ToX11CursorOzone(cursor)->AddRef();
}

void X11CursorFactoryOzone::UnrefImageCursor(PlatformCursor cursor) {
ToX11CursorOzone(cursor)->Release();
}

scoped_refptr<X11CursorOzone> X11CursorFactoryOzone::GetDefaultCursorInternal(
int type) {
if (type == kCursorNone)
return invisible_cursor_;

// TODO(kylechar): Use predefined X cursors here instead.
if (!default_cursors_.count(type)) {
// Loads the default aura cursor bitmap for cursor type. Falls back on
// pointer cursor then invisible cursor if this fails.
scoped_refptr<X11CursorOzone> cursor = CreateAuraX11Cursor(type);
if (!cursor.get()) {
if (type != kCursorPointer) {
cursor = GetDefaultCursorInternal(kCursorPointer);
} else {
NOTREACHED() << "Failed to load default cursor bitmap";
}
}
default_cursors_[type] = cursor;
}

// Returns owned default cursor for this type.
return default_cursors_[type];
}

} // namespace ui
52 changes: 52 additions & 0 deletions ui/ozone/platform/x11/x11_cursor_factory_ozone.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright 2016 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_OZONE_PLATFORM_X11_X11_CURSOR_FACTORY_OZONE_H_
#define UI_OZONE_PLATFORM_X11_X11_CURSOR_FACTORY_OZONE_H_

#include <X11/X.h>

#include <unordered_map>
#include <vector>

#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "ui/base/cursor/cursor.h"
#include "ui/ozone/public/cursor_factory_ozone.h"
#include "ui/platform_window/x11/x11_cursor_ozone.h"

namespace ui {

// CursorFactoryOzone implementation for X11 cursors.
class X11CursorFactoryOzone : public CursorFactoryOzone {
public:
X11CursorFactoryOzone();
~X11CursorFactoryOzone() override;

// CursorFactoryOzone:
PlatformCursor GetDefaultCursor(int type) override;
PlatformCursor CreateImageCursor(const SkBitmap& bitmap,
const gfx::Point& hotspot) override;
PlatformCursor CreateAnimatedCursor(const std::vector<SkBitmap>& bitmaps,
const gfx::Point& hotspot,
int frame_delay_ms) override;
void RefImageCursor(PlatformCursor cursor) override;
void UnrefImageCursor(PlatformCursor cursor) override;

private:
// Loads/caches default cursor or returns cached version.
scoped_refptr<X11CursorOzone> GetDefaultCursorInternal(int type);

// Holds a single instance of the invisible cursor. X11 has no way to hide
// the cursor so an invisible cursor mimics that.
scoped_refptr<X11CursorOzone> invisible_cursor_;

std::unordered_map<int, scoped_refptr<X11CursorOzone>> default_cursors_;

DISALLOW_COPY_AND_ASSIGN(X11CursorFactoryOzone);
};

} // namespace ui

#endif // UI_OZONE_PLATFORM_X11_X11_CURSOR_FACTORY_OZONE_H_
3 changes: 3 additions & 0 deletions ui/platform_window/x11/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@ component("x11") {

if (ozone_platform_x11) {
sources += [
"x11_cursor_ozone.cc",
"x11_cursor_ozone.h",
"x11_window_ozone.cc",
"x11_window_ozone.h",
]
deps += [ "//ui/base" ]
} else if (use_x11) {
sources += [
"x11_window.cc",
Expand Down
2 changes: 2 additions & 0 deletions ui/platform_window/x11/DEPS
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
include_rules = [
"+third_party/skia/include",
"+ui/base/x",
"+ui/events",
"+ui/gfx",
]
84 changes: 84 additions & 0 deletions ui/platform_window/x11/x11_cursor_ozone.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright 2016 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/platform_window/x11/x11_cursor_ozone.h"

#include <X11/Xcursor/Xcursor.h>
#include <X11/Xlib.h>

#include "base/logging.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/geometry/point.h"

namespace ui {

namespace {

// Converts a SKBitmap to unpremul alpha.
SkBitmap ConvertSkBitmapToUnpremul(const SkBitmap& bitmap) {
DCHECK_NE(bitmap.alphaType(), kUnpremul_SkAlphaType);

SkImageInfo image_info = SkImageInfo::MakeN32(bitmap.width(), bitmap.height(),
kUnpremul_SkAlphaType);
SkBitmap converted_bitmap;
converted_bitmap.allocPixels(image_info);
bitmap.readPixels(image_info, converted_bitmap.getPixels(),
image_info.minRowBytes(), 0, 0);

return converted_bitmap;
}

// Creates an XCursorImage for cursor bitmap.
XcursorImage* CreateXCursorImage(const SkBitmap& bitmap,
const gfx::Point& hotspot) {
// X11 expects bitmap with unpremul alpha. If bitmap is premul then convert,
// otherwise semi-transparent parts of cursor will look strange.
if (bitmap.alphaType() != kUnpremul_SkAlphaType) {
SkBitmap converted_bitmap = ConvertSkBitmapToUnpremul(bitmap);
return SkBitmapToXcursorImage(&converted_bitmap, hotspot);
} else {
return SkBitmapToXcursorImage(&bitmap, hotspot);
}
}

} // namespace

X11CursorOzone::X11CursorOzone(const SkBitmap& bitmap,
const gfx::Point& hotspot) {
XcursorImage* image = CreateXCursorImage(bitmap, hotspot);
xcursor_ = XcursorImageLoadCursor(gfx::GetXDisplay(), image);
XcursorImageDestroy(image);
}

X11CursorOzone::X11CursorOzone(const std::vector<SkBitmap>& bitmaps,
const gfx::Point& hotspot,
int frame_delay_ms) {
// Initialize an XCursorImage for each frame, store all of them in
// XCursorImages and load the cursor from that.
XcursorImages* images = XcursorImagesCreate(bitmaps.size());
images->nimage = bitmaps.size();
for (size_t frame = 0; frame < bitmaps.size(); ++frame) {
XcursorImage* x_image = CreateXCursorImage(bitmaps[frame], hotspot);
x_image->delay = frame_delay_ms;
images->images[frame] = x_image;
}

xcursor_ = XcursorImagesLoadCursor(gfx::GetXDisplay(), images);
XcursorImagesDestroy(images);
}

scoped_refptr<X11CursorOzone> X11CursorOzone::CreateInvisible() {
scoped_refptr<X11CursorOzone> invisible_ = new X11CursorOzone();
invisible_->xcursor_ = CreateInvisibleCursor();
return invisible_;
}

X11CursorOzone::X11CursorOzone() {}

X11CursorOzone::~X11CursorOzone() {
XFreeCursor(gfx::GetXDisplay(), xcursor_);
}

} // namespace ui
48 changes: 48 additions & 0 deletions ui/platform_window/x11/x11_cursor_ozone.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2016 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_PLATFORM_WINDOW_X11_X11_CURSOR_OZONE_H_
#define UI_PLATFORM_WINDOW_X11_X11_CURSOR_OZONE_H_

#include <X11/X.h>

#include <vector>

#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "ui/base/cursor/cursor.h"
#include "ui/platform_window/x11/x11_window_export.h"

class SkBitmap;

namespace ui {

// Ref counted class to hold an X11 cursor resource. Handles creating X11 cursor
// resources from SkBitmap/hotspot and clears the X11 resources on destruction.
class X11_WINDOW_EXPORT X11CursorOzone
: public base::RefCounted<X11CursorOzone> {
public:
X11CursorOzone(const SkBitmap& bitmap, const gfx::Point& hotspot);
X11CursorOzone(const std::vector<SkBitmap>& bitmaps,
const gfx::Point& hotspot,
int frame_delay_ms);

// Creates a new cursor that is invisible.
static scoped_refptr<X11CursorOzone> CreateInvisible();

::Cursor xcursor() const { return xcursor_; }

private:
friend class base::RefCounted<X11CursorOzone>;

X11CursorOzone();
~X11CursorOzone();

::Cursor xcursor_ = None;

DISALLOW_COPY_AND_ASSIGN(X11CursorOzone);
};

} // namespace ui
#endif // UI_PLATFORM_WINDOW_X11_X11_CURSOR_OZONE_H_
Loading

0 comments on commit d642dcb

Please sign in to comment.