Commit 2b7551c5 authored by Antonio Gomes's avatar Antonio Gomes Committed by Commit Bot

[ozone/wayand] Implement cursor support

CL makes use of the existing BitmapCursorFactoryOzone implementation
to add pointer/mouse cursor support to Ozone/Wayland.

Implementation of wayland_cursor.cc|h is originally based on [1].

[1] https://github.com/01org/ozone-wayland/

TEST=chrome --mash/mus --ozone-platform=wayland

BUG=578890

Change-Id: Iccd0a23dd1329bfe32ac78af9379ba3fd739d63f
Reviewed-on: https://chromium-review.googlesource.com/644946
Commit-Queue: Antonio Gomes <tonikitoo@igalia.com>
Reviewed-by: default avatarMichael Spang <spang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#515990}
parent 6dd09a38
......@@ -20,6 +20,8 @@ source_set("wayland") {
"ozone_platform_wayland.h",
"wayland_connection.cc",
"wayland_connection.h",
"wayland_cursor.cc",
"wayland_cursor.h",
"wayland_keyboard.cc",
"wayland_keyboard.h",
"wayland_object.cc",
......@@ -53,6 +55,7 @@ source_set("wayland") {
"//skia",
"//third_party/wayland:wayland_client",
"//third_party/wayland-protocols:xdg_shell_protocol",
"//ui/base",
"//ui/base:ui_features",
"//ui/display/manager",
"//ui/events",
......
......@@ -5,6 +5,7 @@
#include "ui/ozone/platform/wayland/ozone_platform_wayland.h"
#include "base/memory/ptr_util.h"
#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
#include "ui/base/ui_features.h"
#include "ui/display/manager/fake_display_delegate.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
......@@ -13,7 +14,6 @@
#include "ui/ozone/platform/wayland/wayland_connection.h"
#include "ui/ozone/platform/wayland/wayland_surface_factory.h"
#include "ui/ozone/platform/wayland/wayland_window.h"
#include "ui/ozone/public/cursor_factory_ozone.h"
#include "ui/ozone/public/gpu_platform_support_host.h"
#include "ui/ozone/public/input_controller.h"
#include "ui/ozone/public/ozone_platform.h"
......@@ -88,7 +88,7 @@ class OzonePlatformWayland : public OzonePlatform {
std::make_unique<StubKeyboardLayoutEngine>());
#endif
cursor_factory_.reset(new CursorFactoryOzone);
cursor_factory_.reset(new BitmapCursorFactoryOzone);
overlay_manager_.reset(new StubOverlayManager);
input_controller_ = CreateStubInputController();
surface_factory_.reset(new WaylandSurfaceFactory(connection_.get()));
......@@ -114,7 +114,7 @@ class OzonePlatformWayland : public OzonePlatform {
private:
std::unique_ptr<WaylandConnection> connection_;
std::unique_ptr<WaylandSurfaceFactory> surface_factory_;
std::unique_ptr<CursorFactoryOzone> cursor_factory_;
std::unique_ptr<BitmapCursorFactoryOzone> cursor_factory_;
std::unique_ptr<StubOverlayManager> overlay_manager_;
std::unique_ptr<InputController> input_controller_;
std::unique_ptr<GpuPlatformSupportHost> gpu_platform_support_host_;
......
......@@ -116,6 +116,13 @@ WaylandOutput* WaylandConnection::PrimaryOutput() const {
return output_list_.front().get();
}
void WaylandConnection::SetCursorBitmap(const std::vector<SkBitmap>& bitmaps,
const gfx::Point& location) {
if (!pointer_ || !pointer_->cursor())
return;
pointer_->cursor()->UpdateBitmap(bitmaps, location, serial_);
}
void WaylandConnection::OnDispatcherListChanged() {
StartProcessingEvents();
}
......@@ -239,6 +246,7 @@ void WaylandConnection::Capabilities(void* data,
connection->pointer_ = std::make_unique<WaylandPointer>(
pointer, base::Bind(&WaylandConnection::DispatchUiEvent,
base::Unretained(connection)));
connection->pointer_->set_connection(connection);
}
} else if (connection->pointer_) {
connection->pointer_.reset();
......@@ -253,6 +261,7 @@ void WaylandConnection::Capabilities(void* data,
connection->keyboard_ = std::make_unique<WaylandKeyboard>(
keyboard, base::Bind(&WaylandConnection::DispatchUiEvent,
base::Unretained(connection)));
connection->keyboard_->set_connection(connection);
}
} else if (connection->keyboard_) {
connection->keyboard_.reset();
......
......@@ -44,6 +44,12 @@ class WaylandConnection : public PlatformEventSource,
const std::vector<std::unique_ptr<WaylandOutput>>& GetOutputList() const;
WaylandOutput* PrimaryOutput() const;
void set_serial(uint32_t serial) { serial_ = serial; }
uint32_t serial() { return serial_; }
void SetCursorBitmap(const std::vector<SkBitmap>& bitmaps,
const gfx::Point& location);
private:
void Flush();
void DispatchUiEvent(Event* event);
......@@ -90,6 +96,8 @@ class WaylandConnection : public PlatformEventSource,
bool watching_ = false;
base::MessagePumpLibevent::FileDescriptorWatcher controller_;
uint32_t serial_ = 0;
std::vector<std::unique_ptr<WaylandOutput>> output_list_;
DISALLOW_COPY_AND_ASSIGN(WaylandConnection);
......
// Copyright 2017 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/wayland/wayland_cursor.h"
#include <sys/mman.h>
#include <vector>
#include "base/memory/shared_memory.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/gfx/skia_util.cc"
#include "ui/ozone/platform/wayland/wayland_connection.h"
#include "ui/ozone/platform/wayland/wayland_pointer.h"
namespace ui {
namespace {
const uint32_t kShmFormat = WL_SHM_FORMAT_ARGB8888;
const SkColorType kColorType = kBGRA_8888_SkColorType;
} // namespace
WaylandCursor::WaylandCursor() : shared_memory_(new base::SharedMemory()) {}
void WaylandCursor::Init(wl_pointer* pointer, WaylandConnection* connection) {
if (input_pointer_ == pointer)
return;
input_pointer_ = pointer;
DCHECK(connection);
shm_ = connection->shm();
pointer_surface_.reset(
wl_compositor_create_surface(connection->compositor()));
}
WaylandCursor::~WaylandCursor() {
pointer_surface_.reset();
buffer_.reset();
if (shared_memory_->handle().GetHandle()) {
shared_memory_->Unmap();
shared_memory_->Close();
}
}
void WaylandCursor::UpdateBitmap(const std::vector<SkBitmap>& cursor_image,
const gfx::Point& location,
uint32_t serial) {
if (!input_pointer_)
return;
if (!cursor_image.size()) {
HideCursor(serial);
return;
}
const SkBitmap& image = cursor_image[0];
SkISize size = image.dimensions();
if (size.isEmpty()) {
HideCursor(serial);
return;
}
if (!CreateSHMBuffer(gfx::SkISizeToSize(size))) {
LOG(ERROR) << "Failed to create SHM buffer for Cursor Bitmap.";
wl_pointer_set_cursor(input_pointer_, serial, nullptr, 0, 0);
return;
}
// The |bitmap| contains ARGB image, so update our wl_buffer, which is
// backed by a SkSurface.
SkRect damage;
image.getBounds(&damage);
// Clear to transparent in case |image| is smaller than the canvas.
SkCanvas* canvas = sk_surface_->getCanvas();
canvas->clear(SK_ColorTRANSPARENT);
canvas->drawBitmapRect(image, damage, nullptr);
wl_pointer_set_cursor(input_pointer_, serial, pointer_surface_.get(),
location.x(), location.y());
wl_surface_attach(pointer_surface_.get(), buffer_.get(), 0, 0);
wl_surface_damage(pointer_surface_.get(), 0, 0, size_.width(),
size_.height());
wl_surface_commit(pointer_surface_.get());
}
bool WaylandCursor::CreateSHMBuffer(const gfx::Size& size) {
if (size == size_)
return true;
size_ = size;
SkImageInfo info = SkImageInfo::MakeN32Premul(size_.width(), size_.height());
int stride = info.minRowBytes();
size_t image_buffer_size = info.computeByteSize(stride);
if (image_buffer_size == SK_MaxSizeT)
return false;
if (shared_memory_->handle().GetHandle()) {
shared_memory_->Unmap();
shared_memory_->Close();
}
if (!shared_memory_->CreateAndMapAnonymous(image_buffer_size)) {
LOG(ERROR) << "Create and mmap failed.";
return false;
}
// TODO(tonikitoo): Use SharedMemory::requested_size instead of
// 'image_buffer_size'?
wl::Object<wl_shm_pool> pool;
pool.reset(wl_shm_create_pool(shm_, shared_memory_->handle().GetHandle(),
image_buffer_size));
buffer_.reset(wl_shm_pool_create_buffer(pool.get(), 0, size_.width(),
size_.height(), stride, kShmFormat));
sk_surface_ = SkSurface::MakeRasterDirect(
SkImageInfo::Make(size_.width(), size_.height(), kColorType,
kOpaque_SkAlphaType),
static_cast<uint8_t*>(shared_memory_->memory()), stride);
return true;
}
void WaylandCursor::HideCursor(uint32_t serial) {
size_ = gfx::Size();
wl_pointer_set_cursor(input_pointer_, serial, nullptr, 0, 0);
buffer_.reset();
if (shared_memory_->handle().GetHandle()) {
shared_memory_->Unmap();
shared_memory_->Close();
}
}
} // namespace ui
// Copyright 2017 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_WAYLAND_WAYLAND_CURSOR_H_
#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_CURSOR_H_
#include <wayland-client.h>
#include <vector>
#include "base/macros.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/gfx/geometry/size.h"
#include "ui/ozone/platform/wayland/wayland_object.h"
namespace base {
class SharedMemory;
}
namespace gfx {
class Point;
}
namespace ui {
class WaylandConnection;
// The WaylandCursor class wraps the actual visual representation
// (what users see drawn) of a wl_pointer.
//
// 'pointer' is the Wayland terminology for mouse/mice.
class WaylandCursor {
public:
WaylandCursor();
~WaylandCursor();
void Init(wl_pointer* pointer, WaylandConnection* connection);
// Updates wl_pointer's visual representation with the given bitmap
// image set, at the hotspot specified by 'location'.
void UpdateBitmap(const std::vector<SkBitmap>& bitmaps,
const gfx::Point& location,
uint32_t serial);
private:
bool CreateSHMBuffer(const gfx::Size& size);
void HideCursor(uint32_t serial);
wl_shm* shm_ = nullptr; // Owned by WaylandConnection.
wl_pointer* input_pointer_ = nullptr; // Owned by WaylandPointer.
wl::Object<wl_buffer> buffer_;
wl::Object<wl_surface> pointer_surface_;
std::unique_ptr<base::SharedMemory> shared_memory_;
sk_sp<SkSurface> sk_surface_;
gfx::Size size_;
DISALLOW_COPY_AND_ASSIGN(WaylandCursor);
};
} // namespace ui
#endif // UI_OZONE_PLATFORM_WAYLAND_WAYLAND_CURSOR_H_
......@@ -14,6 +14,7 @@
#include "ui/events/keycodes/dom/keycode_converter.h"
#include "ui/events/ozone/layout/keyboard_layout_engine.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include "ui/ozone/platform/wayland/wayland_connection.h"
#include "ui/ozone/platform/wayland/wayland_window.h"
#if BUILDFLAG(USE_XKBCOMMON)
......@@ -87,6 +88,7 @@ void WaylandKeyboard::Key(void* data,
uint32_t key,
uint32_t state) {
WaylandKeyboard* keyboard = static_cast<WaylandKeyboard*>(data);
keyboard->connection_->set_serial(serial);
DomCode dom_code =
KeycodeConverter::NativeKeycodeToDomCode(key + kXkbKeycodeOffset);
......
......@@ -10,11 +10,17 @@
namespace ui {
class WaylandConnection;
class WaylandKeyboard {
public:
WaylandKeyboard(wl_keyboard* keyboard, const EventDispatchCallback& callback);
virtual ~WaylandKeyboard();
void set_connection(WaylandConnection* connection) {
connection_ = connection;
}
private:
// wl_keyboard_listener
static void Keymap(void* data,
......@@ -49,6 +55,7 @@ class WaylandKeyboard {
int32_t rate,
int32_t delay);
WaylandConnection* connection_ = nullptr;
wl::Object<wl_keyboard> obj_;
EventDispatchCallback callback_;
uint8_t modifiers_ = 0;
......
......@@ -8,6 +8,7 @@
#include <wayland-client.h>
#include "ui/events/event.h"
#include "ui/ozone/platform/wayland/wayland_connection.h"
#include "ui/ozone/platform/wayland/wayland_window.h"
// TODO(forney): Handle version 5 of wl_pointer.
......@@ -23,6 +24,8 @@ WaylandPointer::WaylandPointer(wl_pointer* pointer,
};
wl_pointer_add_listener(obj_.get(), &listener, this);
cursor_.reset(new WaylandCursor);
}
WaylandPointer::~WaylandPointer() {}
......@@ -100,6 +103,7 @@ void WaylandPointer::Button(void* data,
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
type = ET_MOUSE_PRESSED;
pointer->flags_ |= flag;
pointer->connection_->set_serial(serial);
} else {
type = ET_MOUSE_RELEASED;
pointer->flags_ &= ~flag;
......
......@@ -7,6 +7,7 @@
#include "ui/events/ozone/evdev/event_dispatch_callback.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/ozone/platform/wayland/wayland_cursor.h"
#include "ui/ozone/platform/wayland/wayland_object.h"
namespace ui {
......@@ -16,6 +17,13 @@ class WaylandPointer {
WaylandPointer(wl_pointer* pointer, const EventDispatchCallback& callback);
virtual ~WaylandPointer();
void set_connection(WaylandConnection* connection) {
connection_ = connection;
cursor_->Init(obj_.get(), connection_);
}
WaylandCursor* cursor() { return cursor_.get(); }
private:
// wl_pointer_listener
static void Enter(void* data,
......@@ -45,6 +53,8 @@ class WaylandPointer {
uint32_t axis,
wl_fixed_t value);
WaylandConnection* connection_ = nullptr;
std::unique_ptr<WaylandCursor> cursor_;
wl::Object<wl_pointer> obj_;
EventDispatchCallback callback_;
gfx::PointF location_;
......
......@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
#include "ui/events/event.h"
#include "ui/events/ozone/events_ozone.h"
#include "ui/ozone/platform/wayland/wayland_connection.h"
......@@ -163,7 +164,18 @@ void WaylandWindow::Restore() {
}
void WaylandWindow::SetCursor(PlatformCursor cursor) {
NOTIMPLEMENTED();
scoped_refptr<BitmapCursorOzone> bitmap =
BitmapCursorFactoryOzone::GetBitmapCursor(cursor);
if (bitmap_ == bitmap)
return;
bitmap_ = bitmap;
if (bitmap_) {
connection_->SetCursorBitmap(bitmap_->bitmaps(), bitmap_->hotspot());
} else {
connection_->SetCursorBitmap(std::vector<SkBitmap>(), gfx::Point());
}
}
void WaylandWindow::MoveCursorTo(const gfx::Point& location) {
......
......@@ -5,6 +5,7 @@
#ifndef UI_OZONE_PLATFORM_WAYLAND_WAYLAND_WINDOW_H_
#define UI_OZONE_PLATFORM_WAYLAND_WAYLAND_WINDOW_H_
#include "base/memory/ref_counted.h"
#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
......@@ -13,6 +14,7 @@
namespace ui {
class BitmapCursorOzone;
class PlatformWindowDelegate;
class WaylandConnection;
class XDGSurfaceWrapper;
......@@ -87,6 +89,9 @@ class WaylandWindow : public PlatformWindow, public PlatformEventDispatcher {
// know anything about the version.
std::unique_ptr<XDGSurfaceWrapper> xdg_surface_;
// The current cursor bitmap (immutable).
scoped_refptr<BitmapCursorOzone> bitmap_;
gfx::Rect bounds_;
gfx::Rect pending_bounds_;
bool has_pointer_focus_ = false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment