Use custom native mouse cursor on Skia/OSX port

This commit is contained in:
David Capello 2016-08-30 16:12:11 -03:00
parent 507e0f152b
commit 162cee2870
7 changed files with 131 additions and 37 deletions

View File

@ -17,6 +17,8 @@
#include "she/native_cursor.h"
namespace she {
class Surface;
KeyScancode cocoavk_to_scancode(UInt16 vk);
}
@ -48,6 +50,9 @@ public:
- (gfx::Size)restoredSize;
- (void)setMousePosition:(const gfx::Point&)position;
- (BOOL)setNativeMouseCursor:(she::NativeCursor)cursor;
- (BOOL)setNativeMouseCursor:(const she::Surface*)surface
focus:(const gfx::Point&)focus
scale:(const int)scale;
@end
#endif

View File

@ -14,6 +14,7 @@
#include "she/osx/event_queue.h"
#include "she/osx/view.h"
#include "she/osx/window_delegate.h"
#include "she/surface.h"
using namespace she;
@ -107,7 +108,7 @@ using namespace she;
- (BOOL)setNativeMouseCursor:(NativeCursor)cursor
{
NSCursor* nsCursor = nil;
NSCursor* nsCursor = nullptr;
switch (cursor) {
case kArrowCursor:
@ -149,13 +150,70 @@ using namespace she;
case kSizeWCursor:
nsCursor = [NSCursor resizeLeftCursor];
break;
default:
nsCursor = nil;
break;
}
[self.contentView setCursor:nsCursor];
return (nsCursor != nil ? YES: NO);
return (nsCursor ? YES: NO);
}
- (BOOL)setNativeMouseCursor:(const she::Surface*)surface
focus:(const gfx::Point&)focus
scale:(const int)scale
{
ASSERT(surface);
SurfaceFormatData format;
surface->getFormat(&format);
if (format.bitsPerPixel != 32)
return NO;
const int w = scale*surface->width();
const int h = scale*surface->height();
std::vector<uint32_t> buf(4*w*h);
uint32_t* bits = &buf[0];
for (int y=0; y<h; ++y) {
const uint32_t* ptr = (const uint32_t*)surface->getData(0, y/scale);
for (int x=0, u=0; x<w; ++x, ++bits) {
*bits = *ptr;
if (++u == scale) {
u = 0;
++ptr;
}
}
}
CGDataProviderRef dataRef =
CGDataProviderCreateWithData(nullptr, &buf[0],
w*h*4, nullptr);
if (!dataRef)
return NO;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGImageRef img =
CGImageCreate(
w, h, 8, 32, 4*w,
colorSpace, kCGImageAlphaLast, dataRef,
nullptr, false, kCGRenderingIntentDefault);
CGColorSpaceRelease(colorSpace);
CGDataProviderRelease(dataRef);
NSCursor* nsCursor = nullptr;
if (img) {
NSImage* image =
[[NSImage new] initWithCGImage:img
size:NSMakeSize(w, h)];
CGImageRelease(img);
nsCursor =
[[NSCursor new] initWithImage:image
hotSpot:NSMakePoint(scale*focus.x,
scale*focus.y)];
}
if (nsCursor)
[self.contentView setCursor:nsCursor];
return (nsCursor ? YES: NO);
}
- (void)noResponderFor:(SEL)eventSelector

View File

@ -151,10 +151,10 @@ bool SkiaDisplay::setNativeMouseCursor(const she::Surface* surface,
const gfx::Point& focus,
const int scale)
{
#ifdef _WIN32
#if defined(_WIN32) || defined(__APPLE__)
return m_window.setNativeMouseCursor(surface, focus, scale);
#else
// TODO
// TODO impl this for Linux
return false;
#endif
}

View File

@ -70,7 +70,7 @@ public:
int(Capabilities::MultipleDisplays) |
int(Capabilities::CanResizeDisplay) |
int(Capabilities::DisplayScale)
#ifdef _WIN32
#if defined(_WIN32) || defined(__APPLE__)
| int(Capabilities::CustomNativeMouseCursor)
#endif
// TODO enable this when the GPU support is ready

View File

@ -17,6 +17,7 @@ namespace she {
class EventQueue;
class SkiaDisplay;
class Surface;
class SkiaWindow {
public:
@ -39,6 +40,9 @@ public:
void releaseMouse();
void setMousePosition(const gfx::Point& position);
bool setNativeMouseCursor(NativeCursor cursor);
bool setNativeMouseCursor(const Surface* surface,
const gfx::Point& focus,
const int scale);
void updateWindow(const gfx::Rect& bounds);
std::string getLayout() { return ""; }
void setLayout(const std::string& layout) { }

View File

@ -100,6 +100,14 @@ public:
return ([m_window setNativeMouseCursor:cursor] ? true: false);
}
bool setNativeMouseCursor(const she::Surface* surface,
const gfx::Point& focus,
const int scale) {
return ([m_window setNativeMouseCursor:surface
focus:focus
scale:scale] ? true: false);
}
void updateWindow(const gfx::Rect& bounds) {
int scale = this->scale();
NSView* view = m_window.contentView;
@ -424,6 +432,16 @@ bool SkiaWindow::setNativeMouseCursor(NativeCursor cursor)
return false;
}
bool SkiaWindow::setNativeMouseCursor(const Surface* surface,
const gfx::Point& focus,
const int scale)
{
if (m_impl)
return m_impl->setNativeMouseCursor(surface, focus, scale);
else
return false;
}
void SkiaWindow::updateWindow(const gfx::Rect& bounds)
{
if (m_impl)

View File

@ -45,27 +45,6 @@ static void update_mouse_overlay(Cursor* cursor)
{
mouse_cursor = cursor;
// Check if we can use a custom native mouse in this platform
if (!use_native_mouse_cursor &&
support_native_custom_cursor &&
mouse_display) {
if (cursor) {
if (mouse_display->setNativeMouseCursor(
// The surface is already scaled by guiscale()
cursor->getSurface(),
cursor->getFocus(),
// We scale the cursor by the she::Display scale
mouse_display->scale())) {
return;
}
}
else {
if (mouse_display->setNativeMouseCursor(she::kNoCursor)) {
return;
}
}
}
if (mouse_cursor && mouse_scares == 0) {
if (!mouse_cursor_overlay) {
mouse_cursor_overlay = new Overlay(
@ -88,10 +67,35 @@ static void update_mouse_overlay(Cursor* cursor)
}
}
static bool update_custom_native_cursor(Cursor* cursor)
{
bool result = false;
// Check if we can use a custom native mouse in this platform
if (!use_native_mouse_cursor &&
support_native_custom_cursor &&
mouse_display) {
if (cursor) {
result = mouse_display->setNativeMouseCursor(
// The surface is already scaled by guiscale()
cursor->getSurface(),
cursor->getFocus(),
// We scale the cursor by the she::Display scale
mouse_display->scale());
}
else if (mouse_cursor_type == kOutsideDisplay) {
result = mouse_display->setNativeMouseCursor(she::kArrowCursor);
}
else {
result = mouse_display->setNativeMouseCursor(she::kNoCursor);
}
}
return result;
}
static void update_mouse_cursor()
{
// Use native cursor when it's possible/available/configured to do so.
she::NativeCursor nativeCursor = she::kNoCursor;
Cursor* cursor = nullptr;
@ -140,15 +144,18 @@ static void update_mouse_cursor()
nativeCursor = she::kNoCursor;
}
// Use a software cursor with the overlay.
// Use a custom cursor
if (nativeCursor == she::kNoCursor &&
mouse_cursor_type != ui::kOutsideDisplay &&
CurrentTheme::get()) {
cursor = CurrentTheme::get()->getCursor(mouse_cursor_type);
}
// Set internal overlay
update_mouse_overlay(cursor);
// Try to use a custom native cursor if it's possible
if (!update_custom_native_cursor(cursor)) {
// Or an overlay as last resource
update_mouse_overlay(cursor);
}
}
UISystem::UISystem()
@ -171,8 +178,9 @@ UISystem::~UISystem()
details::exitWidgets();
_internal_set_mouse_display(NULL);
update_mouse_overlay(NULL);
_internal_set_mouse_display(nullptr);
if (!update_custom_native_cursor(nullptr))
update_mouse_overlay(nullptr);
}
void _internal_set_mouse_display(she::Display* display)
@ -249,7 +257,8 @@ void show_mouse_cursor()
void _internal_no_mouse_position()
{
update_mouse_overlay(NULL);
if (!update_custom_native_cursor(nullptr))
update_mouse_overlay(nullptr);
}
void _internal_set_mouse_position(const gfx::Point& newPos)