Implement reusable cursors on macOS
parent
6c4c406211
commit
3d501ef57e
|
@ -291,6 +291,75 @@ static int is_cursor_locked(lua_State *L)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cursor_metatable;
|
||||||
|
|
||||||
|
static void *load_custom_cursor(lua_State *L, int index)
|
||||||
|
{
|
||||||
|
#ifdef DM_PLATFORM_WINDOWS
|
||||||
|
const char *cursor_path_lua = luaL_checkstring(L, index);
|
||||||
|
return defos_load_cursor_win(cursor_path_lua);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DM_PLATFORM_LINUX
|
||||||
|
const char *cursor_path_lua = luaL_checkstring(L, index);
|
||||||
|
return defos_load_cursor_linux(cursor_path_lua);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// TODO: X11 support animated cursor by XRender
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DM_PLATFORM_OSX
|
||||||
|
luaL_checktype(L, index, LUA_TTABLE);
|
||||||
|
|
||||||
|
lua_getfield(L, index, "hot_spot_x");
|
||||||
|
float hotSpotX = 0.0f;
|
||||||
|
if (!lua_isnil(L, -1))
|
||||||
|
{
|
||||||
|
hotSpotX = luaL_checknumber(L, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_getfield(L, index, "hot_spot_y");
|
||||||
|
float hotSpotY = 0.0f;
|
||||||
|
if (!lua_isnil(L, -1))
|
||||||
|
{
|
||||||
|
hotSpotY = luaL_checknumber(L, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_getfield(L, index, "image");
|
||||||
|
dmBuffer::HBuffer image = dmScript::CheckBuffer(L, -1)->m_Buffer;
|
||||||
|
|
||||||
|
void *cursor = defos_load_cursor_mac(image, hotSpotX, hotSpotY);
|
||||||
|
lua_pop(L, 3);
|
||||||
|
return cursor;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DM_PLATFORM_HTML5
|
||||||
|
const char * cursor_url = luaL_checkstring(L, 1);
|
||||||
|
return defos_load_cursor_html5(cursor_url);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lua_pushstring(L, "Invalid argument");
|
||||||
|
lua_error(L);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int load_cursor(lua_State *L)
|
||||||
|
{
|
||||||
|
void ** userdata = (void**)lua_newuserdata(L, sizeof(void*));
|
||||||
|
*userdata = load_custom_cursor(L, 1);
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, cursor_metatable);
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gc_cursor(lua_State *L)
|
||||||
|
{
|
||||||
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
||||||
|
void **cursor = (void**)lua_touserdata(L, 1);
|
||||||
|
defos_gc_custom_cursor(*cursor);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int set_cursor(lua_State *L)
|
static int set_cursor(lua_State *L)
|
||||||
{
|
{
|
||||||
if (lua_isnil(L, 1))
|
if (lua_isnil(L, 1))
|
||||||
|
@ -306,53 +375,16 @@ static int set_cursor(lua_State *L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DM_PLATFORM_WINDOWS
|
if (lua_isuserdata(L, 1))
|
||||||
const char *cursor_path_lua = luaL_checkstring(L, 1);
|
|
||||||
defos_set_custom_cursor_win(cursor_path_lua);
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DM_PLATFORM_LINUX
|
|
||||||
const char *cursor_path_lua = luaL_checkstring(L,1);
|
|
||||||
defos_set_custom_cursor_linux(cursor_path_lua);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// TODO: X11 support animated cursor by XRender
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DM_PLATFORM_OSX
|
|
||||||
luaL_checktype(L, 1, LUA_TTABLE);
|
|
||||||
|
|
||||||
lua_getfield(L, 1, "hot_spot_x");
|
|
||||||
float hotSpotX = 0.0f;
|
|
||||||
if (!lua_isnil(L, -1))
|
|
||||||
{
|
{
|
||||||
hotSpotX = luaL_checknumber(L, -1);
|
void **cursor = (void**)lua_touserdata(L, 1);
|
||||||
|
defos_set_custom_cursor(*cursor);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_getfield(L, 1, "hot_spot_y");
|
void *custom_cursor = load_custom_cursor(L, 1);
|
||||||
float hotSpotY = 0.0f;
|
defos_set_custom_cursor(custom_cursor);
|
||||||
if (!lua_isnil(L, -1))
|
defos_gc_custom_cursor(custom_cursor);
|
||||||
{
|
|
||||||
hotSpotY = luaL_checknumber(L, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
lua_getfield(L, 1, "image");
|
|
||||||
dmBuffer::HBuffer image = dmScript::CheckBuffer(L, -1)->m_Buffer;
|
|
||||||
|
|
||||||
defos_set_custom_cursor_mac(image, hotSpotX, hotSpotY);
|
|
||||||
lua_pop(L, 3);
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DM_PLATFORM_HTML5
|
|
||||||
const char * cursor_url = luaL_checkstring(L, 1);
|
|
||||||
defos_set_custom_cursor_html5(cursor_url);
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
lua_pushstring(L, "Invalid argument");
|
|
||||||
lua_error(L);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,6 +636,7 @@ static const luaL_reg Module_methods[] =
|
||||||
{"get_view_size", get_view_size},
|
{"get_view_size", get_view_size},
|
||||||
{"set_cursor", set_cursor},
|
{"set_cursor", set_cursor},
|
||||||
{"reset_cursor", reset_cursor},
|
{"reset_cursor", reset_cursor},
|
||||||
|
{"load_cursor", load_cursor},
|
||||||
{"get_displays", get_displays},
|
{"get_displays", get_displays},
|
||||||
{"get_display_modes", get_display_modes},
|
{"get_display_modes", get_display_modes},
|
||||||
{"get_current_display_id", get_current_display_id},
|
{"get_current_display_id", get_current_display_id},
|
||||||
|
@ -635,6 +668,11 @@ static void LuaInit(lua_State *L)
|
||||||
lua_setfield(L, -2, "PATH_SEP");
|
lua_setfield(L, -2, "PATH_SEP");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
lua_newtable(L);
|
||||||
|
lua_pushcfunction(L, gc_cursor);
|
||||||
|
lua_setfield(L, -2, "__gc");
|
||||||
|
cursor_metatable = dmScript::Ref(L, LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
assert(top == lua_gettop(L));
|
assert(top == lua_gettop(L));
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ void defos_init() {
|
||||||
// [window disableCursorRects];
|
// [window disableCursorRects];
|
||||||
// [window resetCursorRects];
|
// [window resetCursorRects];
|
||||||
default_cursor = NSCursor.arrowCursor;
|
default_cursor = NSCursor.arrowCursor;
|
||||||
|
[default_cursor retain];
|
||||||
current_cursor = default_cursor;
|
current_cursor = default_cursor;
|
||||||
[current_cursor retain];
|
[current_cursor retain];
|
||||||
enable_mouse_tracking();
|
enable_mouse_tracking();
|
||||||
|
@ -60,8 +61,10 @@ void defos_init() {
|
||||||
|
|
||||||
void defos_final() {
|
void defos_final() {
|
||||||
disable_mouse_tracking();
|
disable_mouse_tracking();
|
||||||
|
[default_cursor release];
|
||||||
[current_cursor release];
|
[current_cursor release];
|
||||||
current_cursor = nil;
|
current_cursor = nil;
|
||||||
|
default_cursor = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
void defos_update() {
|
void defos_update() {
|
||||||
|
@ -338,24 +341,37 @@ bool defos_is_cursor_locked() {
|
||||||
return is_cursor_locked;
|
return is_cursor_locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
void defos_set_custom_cursor_mac(dmBuffer::HBuffer buffer, float hotSpotX, float hotSpotY) {
|
void *defos_load_cursor_mac(dmBuffer::HBuffer buffer, float hotSpotX, float hotSpotY) {
|
||||||
uint8_t* bytes = NULL;
|
@autoreleasepool {
|
||||||
uint32_t size = 0;
|
uint8_t* bytes = NULL;
|
||||||
if (dmBuffer::GetBytes(buffer, (void**)&bytes, &size) != dmBuffer::RESULT_OK) {
|
uint32_t size = 0;
|
||||||
dmLogError("defos_set_custom_cursor_mac: dmBuffer::GetBytes failed");
|
if (dmBuffer::GetBytes(buffer, (void**)&bytes, &size) != dmBuffer::RESULT_OK) {
|
||||||
return;
|
dmLogError("defos_set_custom_cursor_mac: dmBuffer::GetBytes failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* copy = (uint8_t*)malloc(size);
|
||||||
|
memcpy(copy, bytes, size);
|
||||||
|
NSData * data = [[NSData alloc] initWithBytesNoCopy:copy length:size freeWhenDone:YES];
|
||||||
|
NSImage * image = [[NSImage alloc] initWithData:data];
|
||||||
|
NSCursor * cursor = [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint(hotSpotX, hotSpotY)];
|
||||||
|
|
||||||
|
[image release];
|
||||||
|
[data release];
|
||||||
|
return cursor;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t* copy = (uint8_t*)malloc(size);
|
void defos_gc_custom_cursor(void * _cursor) {
|
||||||
memcpy(copy, bytes, size);
|
NSCursor * cursor = (NSCursor*)_cursor;
|
||||||
NSData * data = [[NSData alloc] initWithBytesNoCopy:copy length:size freeWhenDone:YES];
|
[cursor release];
|
||||||
|
}
|
||||||
|
|
||||||
NSImage * image = [[NSImage alloc] initWithData:data];
|
void defos_set_custom_cursor(void * _cursor) {
|
||||||
NSCursor * cursor = [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint(hotSpotX, hotSpotY)];
|
NSCursor * cursor = (NSCursor*)_cursor;
|
||||||
|
[cursor retain];
|
||||||
[current_cursor release];
|
[current_cursor release];
|
||||||
current_cursor = cursor;
|
current_cursor = cursor;
|
||||||
[image release];
|
|
||||||
[data release];
|
|
||||||
[current_cursor set];
|
[current_cursor set];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,10 +392,10 @@ static NSCursor * get_cursor(DefosCursor cursor) {
|
||||||
|
|
||||||
void defos_set_cursor(DefosCursor cur) {
|
void defos_set_cursor(DefosCursor cur) {
|
||||||
NSCursor * cursor = get_cursor(cur);
|
NSCursor * cursor = get_cursor(cur);
|
||||||
[cursor set];
|
|
||||||
[cursor retain];
|
[cursor retain];
|
||||||
[current_cursor release];
|
[current_cursor release];
|
||||||
current_cursor = cursor;
|
current_cursor = cursor;
|
||||||
|
[current_cursor set];
|
||||||
}
|
}
|
||||||
|
|
||||||
void defos_reset_cursor() {
|
void defos_reset_cursor() {
|
||||||
|
|
|
@ -107,10 +107,12 @@ extern bool defos_is_cursor_clipped();
|
||||||
extern void defos_set_cursor_locked(bool locked);
|
extern void defos_set_cursor_locked(bool locked);
|
||||||
extern bool defos_is_cursor_locked();
|
extern bool defos_is_cursor_locked();
|
||||||
|
|
||||||
extern void defos_set_custom_cursor_html5(const char *url);
|
extern void *defos_load_cursor_html5(const char *url);
|
||||||
extern void defos_set_custom_cursor_win(const char *filename);
|
extern void *defos_load_cursor_win(const char *filename);
|
||||||
extern void defos_set_custom_cursor_mac(dmBuffer::HBuffer buffer, float hotSpotX, float hotSpotY);
|
extern void *defos_load_cursor_mac(dmBuffer::HBuffer buffer, float hotSpotX, float hotSpotY);
|
||||||
extern void defos_set_custom_cursor_linux(const char *filename);
|
extern void *defos_load_cursor_linux(const char *filename);
|
||||||
|
extern void defos_gc_custom_cursor(void *cursor);
|
||||||
|
extern void defos_set_custom_cursor(void *cursor);
|
||||||
extern void defos_set_cursor(DefosCursor cursor);
|
extern void defos_set_cursor(DefosCursor cursor);
|
||||||
extern void defos_reset_cursor();
|
extern void defos_reset_cursor();
|
||||||
|
|
||||||
|
|
|
@ -47,26 +47,26 @@ function init(self)
|
||||||
if system_name == "Linux" then
|
if system_name == "Linux" then
|
||||||
-- NOTE: since Defold cannot load resource without extension, we added .xcur here.
|
-- NOTE: since Defold cannot load resource without extension, we added .xcur here.
|
||||||
-- NOTE: cursor should be normal x11 cursor file that type is: image/x-xcursor
|
-- NOTE: cursor should be normal x11 cursor file that type is: image/x-xcursor
|
||||||
table.insert(self.cursors, extract_to_savefolder("cursor.xcur"))
|
table.insert(self.cursors, defos.load_cursor(extract_to_savefolder("cursor.xcur")))
|
||||||
end
|
end
|
||||||
|
|
||||||
if system_name == "Windows" then
|
if system_name == "Windows" then
|
||||||
for i, v in ipairs({"cursor_01.ani", "cursor_02.ani" }) do
|
for i, v in ipairs({"cursor_01.ani", "cursor_02.ani" }) do
|
||||||
-- load source file and write them to save folder, so that we can access them with fullpath, or you can use bundle_resource
|
-- load source file and write them to save folder, so that we can access them with fullpath, or you can use bundle_resource
|
||||||
table.insert(self.cursors, extract_to_savefolder(v))
|
table.insert(self.cursors, defos.load_cursor(extract_to_savefolder(v)))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if system_name == "Darwin" then
|
if system_name == "Darwin" then
|
||||||
table.insert(self.cursors, {
|
table.insert(self.cursors, defos.load_cursor({
|
||||||
image = resource.load("/resources/cursor_mac.tiff"),
|
image = resource.load("/resources/cursor_mac.tiff"),
|
||||||
hot_spot_x = 18,
|
hot_spot_x = 18,
|
||||||
hot_spot_y = 2,
|
hot_spot_y = 2,
|
||||||
})
|
}))
|
||||||
end
|
end
|
||||||
|
|
||||||
if system_name == "HTML5" then
|
if system_name == "HTML5" then
|
||||||
table.insert(self.cursors, cursor_url)
|
table.insert(self.cursors, defos.load_cursor(cursor_url))
|
||||||
end
|
end
|
||||||
|
|
||||||
defos.on_mouse_enter(function ()
|
defos.on_mouse_enter(function ()
|
||||||
|
|
Loading…
Reference in New Issue