Merge pull request #12814 from guilhermefelipecgs/add_hardware_custom_cursor

Custom hardware-accelerated mouse cursor
This commit is contained in:
Rémi Verschelde 2018-01-03 08:35:59 +01:00 committed by GitHub
commit 6322b0bbb7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 318 additions and 41 deletions

View file

@ -84,7 +84,7 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("warp_mouse_position", "to"), &Input::warp_mouse_position);
ClassDB::bind_method(D_METHOD("action_press", "action"), &Input::action_press);
ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release);
ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event);
BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
@ -92,6 +92,24 @@ void Input::_bind_methods() {
BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);
BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED);
BIND_ENUM_CONSTANT(CURSOR_ARROW);
BIND_ENUM_CONSTANT(CURSOR_IBEAM);
BIND_ENUM_CONSTANT(CURSOR_POINTING_HAND);
BIND_ENUM_CONSTANT(CURSOR_CROSS);
BIND_ENUM_CONSTANT(CURSOR_WAIT);
BIND_ENUM_CONSTANT(CURSOR_BUSY);
BIND_ENUM_CONSTANT(CURSOR_DRAG);
BIND_ENUM_CONSTANT(CURSOR_CAN_DROP);
BIND_ENUM_CONSTANT(CURSOR_FORBIDDEN);
BIND_ENUM_CONSTANT(CURSOR_VSIZE);
BIND_ENUM_CONSTANT(CURSOR_HSIZE);
BIND_ENUM_CONSTANT(CURSOR_BDIAGSIZE);
BIND_ENUM_CONSTANT(CURSOR_FDIAGSIZE);
BIND_ENUM_CONSTANT(CURSOR_MOVE);
BIND_ENUM_CONSTANT(CURSOR_VSPLIT);
BIND_ENUM_CONSTANT(CURSOR_HSPLIT);
BIND_ENUM_CONSTANT(CURSOR_HELP);
ADD_SIGNAL(MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "connected")));
}

View file

@ -51,6 +51,28 @@ public:
MOUSE_MODE_CONFINED
};
#undef CursorShape
enum CursorShape {
CURSOR_ARROW,
CURSOR_IBEAM,
CURSOR_POINTING_HAND,
CURSOR_CROSS,
CURSOR_WAIT,
CURSOR_BUSY,
CURSOR_DRAG,
CURSOR_CAN_DROP,
CURSOR_FORBIDDEN,
CURSOR_VSIZE,
CURSOR_HSIZE,
CURSOR_BDIAGSIZE,
CURSOR_FDIAGSIZE,
CURSOR_MOVE,
CURSOR_VSPLIT,
CURSOR_HSPLIT,
CURSOR_HELP,
CURSOR_MAX
};
void set_mouse_mode(MouseMode p_mode);
MouseMode get_mouse_mode() const;
@ -96,7 +118,7 @@ public:
virtual bool is_emulating_touchscreen() const = 0;
virtual void set_custom_mouse_cursor(const RES &p_cursor, const Vector2 &p_hotspot = Vector2()) = 0;
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) = 0;
virtual void set_mouse_in_window(bool p_in_window) = 0;
virtual String get_joy_button_string(int p_button) = 0;
@ -110,5 +132,6 @@ public:
};
VARIANT_ENUM_CAST(Input::MouseMode);
VARIANT_ENUM_CAST(Input::CursorShape);
#endif // INPUT_H

View file

@ -325,6 +325,7 @@ public:
virtual int get_virtual_keyboard_height() const;
virtual void set_cursor_shape(CursorShape p_shape) = 0;
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) = 0;
virtual bool get_swap_ok_cancel() { return false; }
virtual void dump_memory_to_file(const char *p_file);

View file

@ -275,9 +275,12 @@
</return>
<argument index="0" name="image" type="Resource">
</argument>
<argument index="1" name="hotspot" type="Vector2" default="Vector2( 0, 0 )">
<argument index="1" name="cursor_shape" type="int" default="CURSOR_ARROW">
</argument>
<argument index="2" name="hotspot" type="Vector2" default="Vector2( 0, 0 )">
</argument>
<description>
Set a custom mouse cursor image, which is only visible inside the game window. The hotspot can also be specified. See enum [code]CURSOR_*[/code] for the list of shapes.
</description>
</method>
<method name="set_mouse_mode">

View file

@ -497,26 +497,16 @@ bool InputDefault::is_emulating_touchscreen() const {
return emulate_touch;
}
void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, const Vector2 &p_hotspot) {
/* no longer supported, leaving this for reference to anyone who might want to implement hardware cursors
void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
if (Engine::get_singleton()->is_editor_hint())
return;
if (custom_cursor == p_cursor)
return;
custom_cursor = p_cursor;
if (p_cursor.is_null()) {
set_mouse_mode(MOUSE_MODE_VISIBLE);
//removed, please insist us to implement hardare cursors
//VisualServer::get_singleton()->cursor_set_visible(false);
} else {
Ref<AtlasTexture> atex = custom_cursor;
Rect2 region = atex.is_valid() ? atex->get_region() : Rect2();
set_mouse_mode(MOUSE_MODE_HIDDEN);
VisualServer::get_singleton()->cursor_set_visible(true);
VisualServer::get_singleton()->cursor_set_texture(custom_cursor->get_rid(), p_hotspot, 0, region);
VisualServer::get_singleton()->cursor_set_pos(get_mouse_position());
}
*/
OS::get_singleton()->set_custom_mouse_cursor(p_cursor, (OS::CursorShape)p_shape, p_hotspot);
}
void InputDefault::set_mouse_in_window(bool p_in_window) {

View file

@ -225,7 +225,7 @@ public:
void set_emulate_touch(bool p_emulate);
virtual bool is_emulating_touchscreen() const;
virtual void set_custom_mouse_cursor(const RES &p_cursor, const Vector2 &p_hotspot = Vector2());
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
virtual void set_mouse_in_window(bool p_in_window);
void parse_mapping(String p_mapping);

View file

@ -1107,7 +1107,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
if (cursor.is_valid()) {
//print_line("loaded ok");
Vector2 hotspot = ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image_hotspot");
Input::get_singleton()->set_custom_mouse_cursor(cursor, hotspot);
Input::get_singleton()->set_custom_mouse_cursor(cursor, Input::CURSOR_ARROW, hotspot);
}
}
#ifdef TOOLS_ENABLED

View file

@ -248,6 +248,9 @@ void OS_Android::set_cursor_shape(CursorShape p_shape) {
//android really really really has no mouse.. how amazing..
}
void OS_Android::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
}
void OS_Android::main_loop_begin() {
if (main_loop)

View file

@ -182,6 +182,7 @@ public:
virtual bool can_draw() const;
virtual void set_cursor_shape(CursorShape p_shape);
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
void main_loop_begin();
bool main_loop_iterate();

View file

@ -200,6 +200,10 @@ void OS_Haiku::set_cursor_shape(CursorShape p_shape) {
//ERR_PRINT("set_cursor_shape() NOT IMPLEMENTED");
}
void OS_Haiku::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
// TODO
}
int OS_Haiku::get_screen_count() const {
// TODO: implement get_screen_count()
return 1;

View file

@ -87,6 +87,7 @@ public:
virtual Point2 get_mouse_position() const;
virtual int get_mouse_button_state() const;
virtual void set_cursor_shape(CursorShape p_shape);
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual int get_screen_count() const;
virtual int get_current_screen() const;

View file

@ -490,6 +490,8 @@ String OSIPhone::get_user_data_dir() const {
return data_dir;
};
void OSIPhone::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot){};
String OSIPhone::get_name() {
return "iOS";

View file

@ -173,6 +173,7 @@ public:
virtual int get_virtual_keyboard_height() const;
virtual void set_cursor_shape(CursorShape p_shape);
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual Size2 get_window_size() const;

View file

@ -41,6 +41,7 @@
#include "servers/visual/rasterizer.h"
#include "servers/visual/visual_server_wrap_mt.h"
#include "servers/visual_server.h"
#include <AppKit/NSCursor.h>
#include <ApplicationServices/ApplicationServices.h>
#undef CursorShape
@ -86,6 +87,7 @@ public:
id context;
CursorShape cursor_shape;
NSCursor *cursors[CURSOR_MAX] = { NULL };
MouseMode mouse_mode;
String title;
@ -137,6 +139,7 @@ public:
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
virtual void set_cursor_shape(CursorShape p_shape);
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual void set_mouse_show(bool p_show);
virtual void set_mouse_grab(bool p_grab);

View file

@ -577,8 +577,11 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
return;
if (OS_OSX::singleton->main_loop && OS_OSX::singleton->mouse_mode != OS::MOUSE_MODE_CAPTURED)
OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
if (OS_OSX::singleton->input)
if (OS_OSX::singleton->input) {
OS_OSX::singleton->input->set_mouse_in_window(true);
OS_OSX::singleton->cursor_shape = OS::CURSOR_MAX;
OS_OSX::singleton->set_cursor_shape(OS::CURSOR_ARROW);
}
}
- (void)magnifyWithEvent:(NSEvent *)event {
@ -1240,30 +1243,84 @@ void OS_OSX::set_cursor_shape(CursorShape p_shape) {
if (cursor_shape == p_shape)
return;
switch (p_shape) {
case CURSOR_ARROW: [[NSCursor arrowCursor] set]; break;
case CURSOR_IBEAM: [[NSCursor IBeamCursor] set]; break;
case CURSOR_POINTING_HAND: [[NSCursor pointingHandCursor] set]; break;
case CURSOR_CROSS: [[NSCursor crosshairCursor] set]; break;
case CURSOR_WAIT: [[NSCursor arrowCursor] set]; break;
case CURSOR_BUSY: [[NSCursor arrowCursor] set]; break;
case CURSOR_DRAG: [[NSCursor closedHandCursor] set]; break;
case CURSOR_CAN_DROP: [[NSCursor openHandCursor] set]; break;
case CURSOR_FORBIDDEN: [[NSCursor arrowCursor] set]; break;
case CURSOR_VSIZE: [[NSCursor resizeUpDownCursor] set]; break;
case CURSOR_HSIZE: [[NSCursor resizeLeftRightCursor] set]; break;
case CURSOR_BDIAGSIZE: [[NSCursor arrowCursor] set]; break;
case CURSOR_FDIAGSIZE: [[NSCursor arrowCursor] set]; break;
case CURSOR_MOVE: [[NSCursor arrowCursor] set]; break;
case CURSOR_VSPLIT: [[NSCursor resizeUpDownCursor] set]; break;
case CURSOR_HSPLIT: [[NSCursor resizeLeftRightCursor] set]; break;
case CURSOR_HELP: [[NSCursor arrowCursor] set]; break;
default: {};
if (cursors[p_shape] != NULL) {
[cursors[p_shape] set];
} else {
switch (p_shape) {
case CURSOR_ARROW: [[NSCursor arrowCursor] set]; break;
case CURSOR_IBEAM: [[NSCursor IBeamCursor] set]; break;
case CURSOR_POINTING_HAND: [[NSCursor pointingHandCursor] set]; break;
case CURSOR_CROSS: [[NSCursor crosshairCursor] set]; break;
case CURSOR_WAIT: [[NSCursor arrowCursor] set]; break;
case CURSOR_BUSY: [[NSCursor arrowCursor] set]; break;
case CURSOR_DRAG: [[NSCursor closedHandCursor] set]; break;
case CURSOR_CAN_DROP: [[NSCursor openHandCursor] set]; break;
case CURSOR_FORBIDDEN: [[NSCursor arrowCursor] set]; break;
case CURSOR_VSIZE: [[NSCursor resizeUpDownCursor] set]; break;
case CURSOR_HSIZE: [[NSCursor resizeLeftRightCursor] set]; break;
case CURSOR_BDIAGSIZE: [[NSCursor arrowCursor] set]; break;
case CURSOR_FDIAGSIZE: [[NSCursor arrowCursor] set]; break;
case CURSOR_MOVE: [[NSCursor arrowCursor] set]; break;
case CURSOR_VSPLIT: [[NSCursor resizeUpDownCursor] set]; break;
case CURSOR_HSPLIT: [[NSCursor resizeLeftRightCursor] set]; break;
case CURSOR_HELP: [[NSCursor arrowCursor] set]; break;
default: {};
}
}
cursor_shape = p_shape;
}
void OS_OSX::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
if (p_cursor.is_valid()) {
Ref<Texture> texture = p_cursor;
Ref<Image> image = texture->get_data();
int image_size = 32 * 32;
ERR_FAIL_COND(texture->get_width() != 32 || texture->get_height() != 32);
NSBitmapImageRep *imgrep = [[[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:NULL
pixelsWide:image->get_width()
pixelsHigh:image->get_height()
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:image->get_width() * 4
bitsPerPixel:32] autorelease];
ERR_FAIL_COND(imgrep == nil);
uint8_t *pixels = [imgrep bitmapData];
int len = image->get_width() * image->get_height();
PoolVector<uint8_t> data = image->get_data();
PoolVector<uint8_t>::Read r = data.read();
/* Premultiply the alpha channel */
for (int i = 0; i < len; i++) {
uint8_t alpha = r[i * 4 + 3];
pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255);
pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255);
pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255);
pixels[i * 4 + 3] = alpha;
}
NSImage *nsimage = [[[NSImage alloc] initWithSize:NSMakeSize(image->get_width(), image->get_height())] autorelease];
[nsimage addRepresentation:imgrep];
NSCursor *cursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSMakePoint(p_hotspot.x, p_hotspot.y)];
cursors[p_shape] = cursor;
if (p_shape == CURSOR_ARROW) {
[cursor set];
}
}
}
void OS_OSX::set_mouse_show(bool p_show) {
}

View file

@ -179,6 +179,9 @@ void OS_Server::move_window_to_foreground() {
void OS_Server::set_cursor_shape(CursorShape p_shape) {
}
void OS_Server::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
}
OS::PowerState OS_Server::get_power_state() {
return power_manager->get_power_state();
}

View file

@ -75,6 +75,7 @@ public:
virtual String get_name();
virtual void set_cursor_shape(CursorShape p_shape);
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual void set_mouse_show(bool p_show);
virtual void set_mouse_grab(bool p_grab);

View file

@ -651,6 +651,10 @@ void OSUWP::set_cursor_shape(CursorShape p_shape) {
cursor_shape = p_shape;
}
void OSUWP::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
// TODO
}
Error OSUWP::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) {
return FAILED;

View file

@ -218,6 +218,7 @@ public:
virtual String get_clipboard() const;
void set_cursor_shape(CursorShape p_shape);
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
void set_icon(const Ref<Image> &p_icon);
virtual String get_executable_path() const;

View file

@ -1844,10 +1844,125 @@ void OS_Windows::set_cursor_shape(CursorShape p_shape) {
IDC_HELP
};
SetCursor(LoadCursor(hInstance, win_cursors[p_shape]));
if (cursors[p_shape] != NULL) {
SetCursor(cursors[p_shape]);
} else {
SetCursor(LoadCursor(hInstance, win_cursors[p_shape]));
}
cursor_shape = p_shape;
}
void OS_Windows::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
if (p_cursor.is_valid()) {
Ref<Texture> texture = p_cursor;
Ref<Image> image = texture->get_data();
UINT image_size = 32 * 32;
UINT size = sizeof(UINT) * image_size;
ERR_FAIL_COND(texture->get_width() != 32 || texture->get_height() != 32);
// Create the BITMAP with alpha channel
COLORREF *buffer = (COLORREF *)malloc(sizeof(COLORREF) * image_size);
image->lock();
for (UINT index = 0; index < image_size; index++) {
int column_index = floor(index / 32);
int row_index = index % 32;
Color pcColor = image->get_pixel(row_index, column_index);
*(buffer + index) = image->get_pixel(row_index, column_index).to_argb32();
}
image->unlock();
// Using 4 channels, so 4 * 8 bits
HBITMAP bitmap = CreateBitmap(32, 32, 1, 4 * 8, buffer);
COLORREF clrTransparent = -1;
// Create the AND and XOR masks for the bitmap
HBITMAP hAndMask = NULL;
HBITMAP hXorMask = NULL;
GetMaskBitmaps(bitmap, clrTransparent, hAndMask, hXorMask);
if (NULL == hAndMask || NULL == hXorMask) {
return;
}
// Finally, create the icon
ICONINFO iconinfo = { 0 };
iconinfo.fIcon = FALSE;
iconinfo.xHotspot = p_hotspot.x;
iconinfo.yHotspot = p_hotspot.y;
iconinfo.hbmMask = hAndMask;
iconinfo.hbmColor = hXorMask;
cursors[p_shape] = CreateIconIndirect(&iconinfo);
if (p_shape == CURSOR_ARROW) {
SetCursor(cursors[p_shape]);
}
if (hAndMask != NULL) {
DeleteObject(hAndMask);
}
if (hXorMask != NULL) {
DeleteObject(hXorMask);
}
}
}
void OS_Windows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap) {
// Get the system display DC
HDC hDC = GetDC(NULL);
// Create helper DC
HDC hMainDC = CreateCompatibleDC(hDC);
HDC hAndMaskDC = CreateCompatibleDC(hDC);
HDC hXorMaskDC = CreateCompatibleDC(hDC);
// Get the dimensions of the source bitmap
BITMAP bm;
GetObject(hSourceBitmap, sizeof(BITMAP), &bm);
// Create the mask bitmaps
hAndMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // color
hXorMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // color
// Release the system display DC
ReleaseDC(NULL, hDC);
// Select the bitmaps to helper DC
HBITMAP hOldMainBitmap = (HBITMAP)SelectObject(hMainDC, hSourceBitmap);
HBITMAP hOldAndMaskBitmap = (HBITMAP)SelectObject(hAndMaskDC, hAndMaskBitmap);
HBITMAP hOldXorMaskBitmap = (HBITMAP)SelectObject(hXorMaskDC, hXorMaskBitmap);
// Assign the monochrome AND mask bitmap pixels so that a pixels of the source bitmap
// with 'clrTransparent' will be white pixels of the monochrome bitmap
SetBkColor(hMainDC, clrTransparent);
BitBlt(hAndMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCCOPY);
// Assign the color XOR mask bitmap pixels so that a pixels of the source bitmap
// with 'clrTransparent' will be black and rest the pixels same as corresponding
// pixels of the source bitmap
SetBkColor(hXorMaskDC, RGB(0, 0, 0));
SetTextColor(hXorMaskDC, RGB(255, 255, 255));
BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hAndMaskDC, 0, 0, SRCCOPY);
BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCAND);
// Deselect bitmaps from the helper DC
SelectObject(hMainDC, hOldMainBitmap);
SelectObject(hAndMaskDC, hOldAndMaskBitmap);
SelectObject(hXorMaskDC, hOldXorMaskBitmap);
// Delete the helper DC
DeleteDC(hXorMaskDC);
DeleteDC(hAndMaskDC);
DeleteDC(hMainDC);
}
Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) {
if (p_blocking && r_pipe) {

View file

@ -113,6 +113,7 @@ class OS_Windows : public OS {
bool window_has_focus;
uint32_t last_button_state;
HCURSOR cursors[CURSOR_MAX] = { NULL };
CursorShape cursor_shape;
InputDefault *input;
@ -244,6 +245,8 @@ public:
virtual String get_clipboard() const;
void set_cursor_shape(CursorShape p_shape);
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
void GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap);
void set_icon(const Ref<Image> &p_icon);
virtual String get_executable_path() const;

View file

@ -2205,6 +2205,48 @@ void OS_X11::set_cursor_shape(CursorShape p_shape) {
current_cursor = p_shape;
}
void OS_X11::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
if (p_cursor.is_valid()) {
Ref<Texture> texture = p_cursor;
Ref<Image> image = texture->get_data();
ERR_FAIL_COND(texture->get_width() != 32 || texture->get_height() != 32);
// Create the cursor structure
XcursorImage *cursor_image = XcursorImageCreate(texture->get_width(), texture->get_height());
XcursorUInt image_size = 32 * 32;
XcursorDim size = sizeof(XcursorPixel) * image_size;
cursor_image->version = 1;
cursor_image->size = size;
cursor_image->xhot = p_hotspot.x;
cursor_image->yhot = p_hotspot.y;
// allocate memory to contain the whole file
cursor_image->pixels = (XcursorPixel *)malloc(size);
image->lock();
for (XcursorPixel index = 0; index < image_size; index++) {
int column_index = floor(index / 32);
int row_index = index % 32;
*(cursor_image->pixels + index) = image->get_pixel(row_index, column_index).to_argb32();
}
image->unlock();
ERR_FAIL_COND(cursor_image->pixels == NULL);
// Save it for a further usage
cursors[p_shape] = XcursorImageLoadCursor(x11_display, cursor_image);
if (p_shape == CURSOR_ARROW) {
XDefineCursor(x11_display, x11_window, cursors[p_shape]);
}
}
}
void OS_X11::release_rendering_thread() {
context_gl->release_current();

View file

@ -204,6 +204,7 @@ public:
virtual String get_name();
virtual void set_cursor_shape(CursorShape p_shape);
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
void set_mouse_mode(MouseMode p_mode);
MouseMode get_mouse_mode() const;