mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
ebiten: add more cursor shapes
This change adds these new cursor shapes: * CursorShapeNESWResize * CursorShapeNWSEResize * CursorShapeMove * CursorShapeNotAllowed Closes #2476
This commit is contained in:
parent
269b557e38
commit
91e1c0ea29
16
cursor.go
16
cursor.go
@ -33,10 +33,14 @@ type CursorShapeType = ui.CursorShape
|
|||||||
|
|
||||||
// CursorShapeTypes
|
// CursorShapeTypes
|
||||||
const (
|
const (
|
||||||
CursorShapeDefault CursorShapeType = ui.CursorShapeDefault
|
CursorShapeDefault CursorShapeType = CursorShapeType(ui.CursorShapeDefault)
|
||||||
CursorShapeText CursorShapeType = ui.CursorShapeText
|
CursorShapeText CursorShapeType = CursorShapeType(ui.CursorShapeText)
|
||||||
CursorShapeCrosshair CursorShapeType = ui.CursorShapeCrosshair
|
CursorShapeCrosshair CursorShapeType = CursorShapeType(ui.CursorShapeCrosshair)
|
||||||
CursorShapePointer CursorShapeType = ui.CursorShapePointer
|
CursorShapePointer CursorShapeType = CursorShapeType(ui.CursorShapePointer)
|
||||||
CursorShapeEWResize CursorShapeType = ui.CursorShapeEWResize
|
CursorShapeEWResize CursorShapeType = CursorShapeType(ui.CursorShapeEWResize)
|
||||||
CursorShapeNSResize CursorShapeType = ui.CursorShapeNSResize
|
CursorShapeNSResize CursorShapeType = CursorShapeType(ui.CursorShapeNSResize)
|
||||||
|
CursorShapeNESWResize CursorShapeType = CursorShapeType(ui.CursorShapeNESWResize)
|
||||||
|
CursorShapeNWSEResize CursorShapeType = CursorShapeType(ui.CursorShapeNWSEResize)
|
||||||
|
CursorShapeMove CursorShapeType = CursorShapeType(ui.CursorShapeMove)
|
||||||
|
CursorShapeNotAllowed CursorShapeType = CursorShapeType(ui.CursorShapeNotAllowed)
|
||||||
)
|
)
|
||||||
|
@ -33,6 +33,7 @@ const (
|
|||||||
type Game struct {
|
type Game struct {
|
||||||
grids map[image.Rectangle]ebiten.CursorShapeType
|
grids map[image.Rectangle]ebiten.CursorShapeType
|
||||||
gridColors map[image.Rectangle]color.Color
|
gridColors map[image.Rectangle]color.Color
|
||||||
|
cursor ebiten.CursorShapeType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Game) Update() error {
|
func (g *Game) Update() error {
|
||||||
@ -44,7 +45,12 @@ func (g *Game) Update() error {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call SetCursorShape only when this is changed to test Ebitengine remembers the current cursor correctly even when it is hidden.
|
||||||
|
if g.cursor != cursor {
|
||||||
ebiten.SetCursorShape(cursor)
|
ebiten.SetCursorShape(cursor)
|
||||||
|
g.cursor = cursor
|
||||||
|
}
|
||||||
|
|
||||||
if inpututil.IsKeyJustPressed(ebiten.KeyC) {
|
if inpututil.IsKeyJustPressed(ebiten.KeyC) {
|
||||||
switch ebiten.CursorMode() {
|
switch ebiten.CursorMode() {
|
||||||
@ -76,6 +82,14 @@ func (g *Game) Draw(screen *ebiten.Image) {
|
|||||||
ebitenutil.DebugPrint(screen, "CursorShape: EW Resize")
|
ebitenutil.DebugPrint(screen, "CursorShape: EW Resize")
|
||||||
case ebiten.CursorShapeNSResize:
|
case ebiten.CursorShapeNSResize:
|
||||||
ebitenutil.DebugPrint(screen, "CursorShape: NS Resize")
|
ebitenutil.DebugPrint(screen, "CursorShape: NS Resize")
|
||||||
|
case ebiten.CursorShapeNESWResize:
|
||||||
|
ebitenutil.DebugPrint(screen, "CursorShape: NESW Resize")
|
||||||
|
case ebiten.CursorShapeNWSEResize:
|
||||||
|
ebitenutil.DebugPrint(screen, "CursorShape: NWSE Resize")
|
||||||
|
case ebiten.CursorShapeMove:
|
||||||
|
ebitenutil.DebugPrint(screen, "CursorShape: Move")
|
||||||
|
case ebiten.CursorShapeNotAllowed:
|
||||||
|
ebitenutil.DebugPrint(screen, "CursorShape: Not Allowed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,18 +103,25 @@ func main() {
|
|||||||
image.Rect(100, 100, 200, 200): ebiten.CursorShapeDefault,
|
image.Rect(100, 100, 200, 200): ebiten.CursorShapeDefault,
|
||||||
image.Rect(200, 100, 300, 200): ebiten.CursorShapeText,
|
image.Rect(200, 100, 300, 200): ebiten.CursorShapeText,
|
||||||
image.Rect(300, 100, 400, 200): ebiten.CursorShapeCrosshair,
|
image.Rect(300, 100, 400, 200): ebiten.CursorShapeCrosshair,
|
||||||
image.Rect(100, 200, 200, 300): ebiten.CursorShapePointer,
|
image.Rect(400, 100, 500, 200): ebiten.CursorShapePointer,
|
||||||
image.Rect(200, 200, 300, 300): ebiten.CursorShapeEWResize,
|
image.Rect(100, 200, 200, 300): ebiten.CursorShapeEWResize,
|
||||||
image.Rect(300, 200, 400, 300): ebiten.CursorShapeNSResize,
|
image.Rect(200, 200, 300, 300): ebiten.CursorShapeNSResize,
|
||||||
|
image.Rect(300, 200, 400, 300): ebiten.CursorShapeNESWResize,
|
||||||
|
image.Rect(400, 200, 500, 300): ebiten.CursorShapeNWSEResize,
|
||||||
|
image.Rect(100, 300, 200, 400): ebiten.CursorShapeMove,
|
||||||
|
image.Rect(200, 300, 300, 400): ebiten.CursorShapeNotAllowed,
|
||||||
},
|
},
|
||||||
gridColors: map[image.Rectangle]color.Color{},
|
gridColors: map[image.Rectangle]color.Color{},
|
||||||
}
|
}
|
||||||
for rect, c := range g.grids {
|
for rect, c := range g.grids {
|
||||||
clr := color.RGBA{0x40, 0x40, 0x40, 0xff}
|
clr := color.RGBA{0x40, 0x40, 0x40, 0xff}
|
||||||
if c%2 == 0 {
|
switch c % 3 {
|
||||||
|
case 0:
|
||||||
clr.R = 0x80
|
clr.R = 0x80
|
||||||
} else {
|
case 1:
|
||||||
clr.G = 0x80
|
clr.G = 0x80
|
||||||
|
case 2:
|
||||||
|
clr.B = 0x80
|
||||||
}
|
}
|
||||||
g.gridColors[rect] = clr
|
g.gridColors[rect] = clr
|
||||||
}
|
}
|
||||||
|
@ -1728,18 +1728,64 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
|
|||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
if (shape == GLFW_ARROW_CURSOR)
|
SEL cursorSelector = NULL;
|
||||||
|
|
||||||
|
switch (shape)
|
||||||
|
{
|
||||||
|
case GLFW_HRESIZE_CURSOR:
|
||||||
|
cursorSelector = NSSelectorFromString(@"_windowResizeEastWestCursor");
|
||||||
|
break;
|
||||||
|
case GLFW_VRESIZE_CURSOR:
|
||||||
|
cursorSelector = NSSelectorFromString(@"_windowResizeNorthSouthCursor");
|
||||||
|
break;
|
||||||
|
case GLFW_RESIZE_NWSE_CURSOR:
|
||||||
|
cursorSelector = NSSelectorFromString(@"_windowResizeNorthWestSouthEastCursor");
|
||||||
|
break;
|
||||||
|
case GLFW_RESIZE_NESW_CURSOR:
|
||||||
|
cursorSelector = NSSelectorFromString(@"_windowResizeNorthEastSouthWestCursor");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursorSelector && [NSCursor respondsToSelector:cursorSelector])
|
||||||
|
{
|
||||||
|
id object = [NSCursor performSelector:cursorSelector];
|
||||||
|
if ([object isKindOfClass:[NSCursor class]])
|
||||||
|
cursor->ns.object = object;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cursor->ns.object)
|
||||||
|
{
|
||||||
|
switch (shape)
|
||||||
|
{
|
||||||
|
case GLFW_ARROW_CURSOR:
|
||||||
cursor->ns.object = [NSCursor arrowCursor];
|
cursor->ns.object = [NSCursor arrowCursor];
|
||||||
else if (shape == GLFW_IBEAM_CURSOR)
|
break;
|
||||||
|
case GLFW_IBEAM_CURSOR:
|
||||||
cursor->ns.object = [NSCursor IBeamCursor];
|
cursor->ns.object = [NSCursor IBeamCursor];
|
||||||
else if (shape == GLFW_CROSSHAIR_CURSOR)
|
break;
|
||||||
|
case GLFW_CROSSHAIR_CURSOR:
|
||||||
cursor->ns.object = [NSCursor crosshairCursor];
|
cursor->ns.object = [NSCursor crosshairCursor];
|
||||||
else if (shape == GLFW_HAND_CURSOR)
|
break;
|
||||||
|
case GLFW_HAND_CURSOR:
|
||||||
cursor->ns.object = [NSCursor pointingHandCursor];
|
cursor->ns.object = [NSCursor pointingHandCursor];
|
||||||
else if (shape == GLFW_HRESIZE_CURSOR)
|
break;
|
||||||
cursor->ns.object = [NSCursor resizeLeftRightCursor];
|
case GLFW_RESIZE_ALL_CURSOR:
|
||||||
else if (shape == GLFW_VRESIZE_CURSOR)
|
{
|
||||||
cursor->ns.object = [NSCursor resizeUpDownCursor];
|
// Use the OS's resource: https://stackoverflow.com/a/21786835/5435443
|
||||||
|
NSString *cursorName = @"move";
|
||||||
|
NSString *cursorPath = [@"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/Resources/cursors" stringByAppendingPathComponent:cursorName];
|
||||||
|
NSImage *image = [[NSImage alloc] initByReferencingFile:[cursorPath stringByAppendingPathComponent:@"cursor.pdf"]];
|
||||||
|
NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[cursorPath stringByAppendingPathComponent:@"info.plist"]];
|
||||||
|
cursor->ns.object = [[NSCursor alloc] initWithImage:image
|
||||||
|
hotSpot:NSMakePoint([[info valueForKey:@"hotx"] doubleValue],
|
||||||
|
[[info valueForKey:@"hoty"] doubleValue])];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GLFW_NOT_ALLOWED_CURSOR:
|
||||||
|
cursor->ns.object = [NSCursor operationNotAllowedCursor];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!cursor->ns.object)
|
if (!cursor->ns.object)
|
||||||
{
|
{
|
||||||
|
@ -964,6 +964,12 @@ extern "C" {
|
|||||||
#define GLFW_VRESIZE_CURSOR 0x00036006
|
#define GLFW_VRESIZE_CURSOR 0x00036006
|
||||||
/*! @} */
|
/*! @} */
|
||||||
|
|
||||||
|
// Added in GLFW v3.4.
|
||||||
|
#define GLFW_RESIZE_NWSE_CURSOR 0x00036007
|
||||||
|
#define GLFW_RESIZE_NESW_CURSOR 0x00036008
|
||||||
|
#define GLFW_RESIZE_ALL_CURSOR 0x00036009
|
||||||
|
#define GLFW_NOT_ALLOWED_CURSOR 0x0003600A
|
||||||
|
|
||||||
#define GLFW_CONNECTED 0x00040001
|
#define GLFW_CONNECTED 0x00040001
|
||||||
#define GLFW_DISCONNECTED 0x00040002
|
#define GLFW_DISCONNECTED 0x00040002
|
||||||
|
|
||||||
|
@ -470,7 +470,11 @@ GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape)
|
|||||||
shape != GLFW_CROSSHAIR_CURSOR &&
|
shape != GLFW_CROSSHAIR_CURSOR &&
|
||||||
shape != GLFW_HAND_CURSOR &&
|
shape != GLFW_HAND_CURSOR &&
|
||||||
shape != GLFW_HRESIZE_CURSOR &&
|
shape != GLFW_HRESIZE_CURSOR &&
|
||||||
shape != GLFW_VRESIZE_CURSOR)
|
shape != GLFW_VRESIZE_CURSOR &&
|
||||||
|
shape != GLFW_RESIZE_NWSE_CURSOR &&
|
||||||
|
shape != GLFW_RESIZE_NESW_CURSOR &&
|
||||||
|
shape != GLFW_RESIZE_ALL_CURSOR &&
|
||||||
|
shape != GLFW_NOT_ALLOWED_CURSOR)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor 0x%08X", shape);
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor 0x%08X", shape);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1823,28 +1823,6 @@ const struct wl_data_device_listener dataDeviceListener =
|
|||||||
dataDeviceHandleSelection,
|
dataDeviceHandleSelection,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Translates a GLFW standard cursor to a theme cursor name
|
|
||||||
//
|
|
||||||
static char *translateCursorShape(int shape)
|
|
||||||
{
|
|
||||||
switch (shape)
|
|
||||||
{
|
|
||||||
case GLFW_ARROW_CURSOR:
|
|
||||||
return "left_ptr";
|
|
||||||
case GLFW_IBEAM_CURSOR:
|
|
||||||
return "xterm";
|
|
||||||
case GLFW_CROSSHAIR_CURSOR:
|
|
||||||
return "crosshair";
|
|
||||||
case GLFW_HAND_CURSOR:
|
|
||||||
return "hand2";
|
|
||||||
case GLFW_HRESIZE_CURSOR:
|
|
||||||
return "sb_h_double_arrow";
|
|
||||||
case GLFW_VRESIZE_CURSOR:
|
|
||||||
return "sb_v_double_arrow";
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _glfwAddSeatListenerWayland(struct wl_seat* seat)
|
void _glfwAddSeatListenerWayland(struct wl_seat* seat)
|
||||||
{
|
{
|
||||||
wl_seat_add_listener(seat, &seatListener, NULL);
|
wl_seat_add_listener(seat, &seatListener, NULL);
|
||||||
@ -2392,26 +2370,101 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
|||||||
|
|
||||||
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
|
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
|
||||||
{
|
{
|
||||||
struct wl_cursor* standardCursor;
|
// See GLFW 3.4 implementation.
|
||||||
|
const char* name = NULL;
|
||||||
|
|
||||||
standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,
|
// Try the XDG names first
|
||||||
translateCursorShape(shape));
|
switch (shape)
|
||||||
if (!standardCursor)
|
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
case GLFW_ARROW_CURSOR:
|
||||||
"Wayland: Standard cursor \"%s\" not found",
|
name = "default";
|
||||||
translateCursorShape(shape));
|
break;
|
||||||
return GLFW_FALSE;
|
case GLFW_IBEAM_CURSOR:
|
||||||
|
name = "text";
|
||||||
|
break;
|
||||||
|
case GLFW_CROSSHAIR_CURSOR:
|
||||||
|
name = "crosshair";
|
||||||
|
break;
|
||||||
|
case GLFW_HAND_CURSOR:
|
||||||
|
name = "pointer";
|
||||||
|
break;
|
||||||
|
case GLFW_HRESIZE_CURSOR:
|
||||||
|
name = "ew-resize";
|
||||||
|
break;
|
||||||
|
case GLFW_VRESIZE_CURSOR:
|
||||||
|
name = "ns-resize";
|
||||||
|
break;
|
||||||
|
case GLFW_RESIZE_NWSE_CURSOR:
|
||||||
|
name = "nwse-resize";
|
||||||
|
break;
|
||||||
|
case GLFW_RESIZE_NESW_CURSOR:
|
||||||
|
name = "nesw-resize";
|
||||||
|
break;
|
||||||
|
case GLFW_RESIZE_ALL_CURSOR:
|
||||||
|
name = "all-scroll";
|
||||||
|
break;
|
||||||
|
case GLFW_NOT_ALLOWED_CURSOR:
|
||||||
|
name = "not-allowed";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor->wl.cursor = standardCursor;
|
cursor->wl.cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, name);
|
||||||
cursor->wl.currentImage = 0;
|
|
||||||
|
|
||||||
if (_glfw.wl.cursorThemeHiDPI)
|
if (_glfw.wl.cursorThemeHiDPI)
|
||||||
{
|
{
|
||||||
standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI,
|
cursor->wl.cursorHiDPI =
|
||||||
translateCursorShape(shape));
|
wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, name);
|
||||||
cursor->wl.cursorHiDPI = standardCursor;
|
}
|
||||||
|
|
||||||
|
if (!cursor->wl.cursor)
|
||||||
|
{
|
||||||
|
// Fall back to the core X11 names
|
||||||
|
switch (shape)
|
||||||
|
{
|
||||||
|
case GLFW_ARROW_CURSOR:
|
||||||
|
name = "left_ptr";
|
||||||
|
break;
|
||||||
|
case GLFW_IBEAM_CURSOR:
|
||||||
|
name = "xterm";
|
||||||
|
break;
|
||||||
|
case GLFW_CROSSHAIR_CURSOR:
|
||||||
|
name = "crosshair";
|
||||||
|
break;
|
||||||
|
case GLFW_HAND_CURSOR:
|
||||||
|
name = "hand2";
|
||||||
|
break;
|
||||||
|
case GLFW_HRESIZE_CURSOR:
|
||||||
|
name = "sb_h_double_arrow";
|
||||||
|
break;
|
||||||
|
case GLFW_VRESIZE_CURSOR:
|
||||||
|
name = "sb_v_double_arrow";
|
||||||
|
break;
|
||||||
|
case GLFW_RESIZE_ALL_CURSOR:
|
||||||
|
name = "fleur";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//_glfwInputError(GLFW_CURSOR_UNAVAILABLE,
|
||||||
|
// "Wayland: Standard cursor shape unavailable");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor->wl.cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, name);
|
||||||
|
if (!cursor->wl.cursor)
|
||||||
|
{
|
||||||
|
//_glfwInputError(GLFW_CURSOR_UNAVAILABLE,
|
||||||
|
// "Wayland: Failed to create standard cursor \"%s\"",
|
||||||
|
// name);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.wl.cursorThemeHiDPI)
|
||||||
|
{
|
||||||
|
if (!cursor->wl.cursorHiDPI)
|
||||||
|
{
|
||||||
|
cursor->wl.cursorHiDPI =
|
||||||
|
wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return GLFW_TRUE;
|
return GLFW_TRUE;
|
||||||
|
@ -741,6 +741,12 @@ static GLFWbool initExtensions(void)
|
|||||||
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy");
|
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageDestroy");
|
||||||
_glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor)
|
_glfw.x11.xcursor.ImageLoadCursor = (PFN_XcursorImageLoadCursor)
|
||||||
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor");
|
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorImageLoadCursor");
|
||||||
|
_glfw.x11.xcursor.GetTheme = (PFN_XcursorGetTheme)
|
||||||
|
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorGetTheme");
|
||||||
|
_glfw.x11.xcursor.GetDefaultSize = (PFN_XcursorGetDefaultSize)
|
||||||
|
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorGetDefaultSize");
|
||||||
|
_glfw.x11.xcursor.LibraryLoadImage = (PFN_XcursorLibraryLoadImage)
|
||||||
|
_glfw_dlsym(_glfw.x11.xcursor.handle, "XcursorLibraryLoadImage");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__CYGWIN__)
|
#if defined(__CYGWIN__)
|
||||||
|
@ -87,9 +87,15 @@ typedef int (* PFN_XRRUpdateConfiguration)(XEvent*);
|
|||||||
typedef XcursorImage* (* PFN_XcursorImageCreate)(int,int);
|
typedef XcursorImage* (* PFN_XcursorImageCreate)(int,int);
|
||||||
typedef void (* PFN_XcursorImageDestroy)(XcursorImage*);
|
typedef void (* PFN_XcursorImageDestroy)(XcursorImage*);
|
||||||
typedef Cursor (* PFN_XcursorImageLoadCursor)(Display*,const XcursorImage*);
|
typedef Cursor (* PFN_XcursorImageLoadCursor)(Display*,const XcursorImage*);
|
||||||
|
typedef char* (* PFN_XcursorGetTheme)(Display*);
|
||||||
|
typedef int (* PFN_XcursorGetDefaultSize)(Display*);
|
||||||
|
typedef XcursorImage* (* PFN_XcursorLibraryLoadImage)(const char*,const char*,int);
|
||||||
#define XcursorImageCreate _glfw.x11.xcursor.ImageCreate
|
#define XcursorImageCreate _glfw.x11.xcursor.ImageCreate
|
||||||
#define XcursorImageDestroy _glfw.x11.xcursor.ImageDestroy
|
#define XcursorImageDestroy _glfw.x11.xcursor.ImageDestroy
|
||||||
#define XcursorImageLoadCursor _glfw.x11.xcursor.ImageLoadCursor
|
#define XcursorImageLoadCursor _glfw.x11.xcursor.ImageLoadCursor
|
||||||
|
#define XcursorGetTheme _glfw.x11.xcursor.GetTheme
|
||||||
|
#define XcursorGetDefaultSize _glfw.x11.xcursor.GetDefaultSize
|
||||||
|
#define XcursorLibraryLoadImage _glfw.x11.xcursor.LibraryLoadImage
|
||||||
|
|
||||||
typedef Bool (* PFN_XineramaIsActive)(Display*);
|
typedef Bool (* PFN_XineramaIsActive)(Display*);
|
||||||
typedef Bool (* PFN_XineramaQueryExtension)(Display*,int*,int*);
|
typedef Bool (* PFN_XineramaQueryExtension)(Display*,int*,int*);
|
||||||
@ -327,6 +333,9 @@ typedef struct _GLFWlibraryX11
|
|||||||
PFN_XcursorImageCreate ImageCreate;
|
PFN_XcursorImageCreate ImageCreate;
|
||||||
PFN_XcursorImageDestroy ImageDestroy;
|
PFN_XcursorImageDestroy ImageDestroy;
|
||||||
PFN_XcursorImageLoadCursor ImageLoadCursor;
|
PFN_XcursorImageLoadCursor ImageLoadCursor;
|
||||||
|
PFN_XcursorGetTheme GetTheme;
|
||||||
|
PFN_XcursorGetDefaultSize GetDefaultSize;
|
||||||
|
PFN_XcursorLibraryLoadImage LibraryLoadImage;
|
||||||
} xcursor;
|
} xcursor;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -2908,22 +2908,90 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
|||||||
|
|
||||||
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
|
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
|
||||||
{
|
{
|
||||||
int native = 0;
|
// See GLFW 3.4 implementation.
|
||||||
|
if (_glfw.x11.xcursor.handle)
|
||||||
|
{
|
||||||
|
char* theme = XcursorGetTheme(_glfw.x11.display);
|
||||||
|
if (theme)
|
||||||
|
{
|
||||||
|
const int size = XcursorGetDefaultSize(_glfw.x11.display);
|
||||||
|
const char* name = NULL;
|
||||||
|
|
||||||
if (shape == GLFW_ARROW_CURSOR)
|
switch (shape)
|
||||||
|
{
|
||||||
|
case GLFW_ARROW_CURSOR:
|
||||||
|
name = "default";
|
||||||
|
break;
|
||||||
|
case GLFW_IBEAM_CURSOR:
|
||||||
|
name = "text";
|
||||||
|
break;
|
||||||
|
case GLFW_CROSSHAIR_CURSOR:
|
||||||
|
name = "crosshair";
|
||||||
|
break;
|
||||||
|
case GLFW_HAND_CURSOR:
|
||||||
|
name = "pointer";
|
||||||
|
break;
|
||||||
|
case GLFW_HRESIZE_CURSOR:
|
||||||
|
name = "ew-resize";
|
||||||
|
break;
|
||||||
|
case GLFW_VRESIZE_CURSOR:
|
||||||
|
name = "ns-resize";
|
||||||
|
break;
|
||||||
|
case GLFW_RESIZE_NWSE_CURSOR:
|
||||||
|
name = "nwse-resize";
|
||||||
|
break;
|
||||||
|
case GLFW_RESIZE_NESW_CURSOR:
|
||||||
|
name = "nesw-resize";
|
||||||
|
break;
|
||||||
|
case GLFW_RESIZE_ALL_CURSOR:
|
||||||
|
name = "all-scroll";
|
||||||
|
break;
|
||||||
|
case GLFW_NOT_ALLOWED_CURSOR:
|
||||||
|
name = "not-allowed";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
XcursorImage* image = XcursorLibraryLoadImage(name, theme, size);
|
||||||
|
if (image)
|
||||||
|
{
|
||||||
|
cursor->x11.handle = XcursorImageLoadCursor(_glfw.x11.display, image);
|
||||||
|
XcursorImageDestroy(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cursor->x11.handle)
|
||||||
|
{
|
||||||
|
unsigned int native = 0;
|
||||||
|
|
||||||
|
switch (shape)
|
||||||
|
{
|
||||||
|
case GLFW_ARROW_CURSOR:
|
||||||
native = XC_left_ptr;
|
native = XC_left_ptr;
|
||||||
else if (shape == GLFW_IBEAM_CURSOR)
|
break;
|
||||||
|
case GLFW_IBEAM_CURSOR:
|
||||||
native = XC_xterm;
|
native = XC_xterm;
|
||||||
else if (shape == GLFW_CROSSHAIR_CURSOR)
|
break;
|
||||||
|
case GLFW_CROSSHAIR_CURSOR:
|
||||||
native = XC_crosshair;
|
native = XC_crosshair;
|
||||||
else if (shape == GLFW_HAND_CURSOR)
|
break;
|
||||||
|
case GLFW_HAND_CURSOR:
|
||||||
native = XC_hand2;
|
native = XC_hand2;
|
||||||
else if (shape == GLFW_HRESIZE_CURSOR)
|
break;
|
||||||
|
case GLFW_HRESIZE_CURSOR:
|
||||||
native = XC_sb_h_double_arrow;
|
native = XC_sb_h_double_arrow;
|
||||||
else if (shape == GLFW_VRESIZE_CURSOR)
|
break;
|
||||||
|
case GLFW_VRESIZE_CURSOR:
|
||||||
native = XC_sb_v_double_arrow;
|
native = XC_sb_v_double_arrow;
|
||||||
else
|
break;
|
||||||
|
case GLFW_RESIZE_ALL_CURSOR:
|
||||||
|
native = XC_fleur;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//_glfwInputError(GLFW_CURSOR_UNAVAILABLE,
|
||||||
|
// "X11: Standard cursor shape unavailable");
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native);
|
cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native);
|
||||||
if (!cursor->x11.handle)
|
if (!cursor->x11.handle)
|
||||||
@ -2932,6 +3000,7 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
|
|||||||
"X11: Failed to create standard cursor");
|
"X11: Failed to create standard cursor");
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return GLFW_TRUE;
|
return GLFW_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -141,4 +141,10 @@ const (
|
|||||||
HandCursor = StandardCursor(0x00036004)
|
HandCursor = StandardCursor(0x00036004)
|
||||||
HResizeCursor = StandardCursor(0x00036005)
|
HResizeCursor = StandardCursor(0x00036005)
|
||||||
VResizeCursor = StandardCursor(0x00036006)
|
VResizeCursor = StandardCursor(0x00036006)
|
||||||
|
|
||||||
|
// v3.4
|
||||||
|
ResizeNWSECursor = StandardCursor(0x00036007)
|
||||||
|
ResizeNESWCursor = StandardCursor(0x00036008)
|
||||||
|
ResizeAllCursor = StandardCursor(0x00036009)
|
||||||
|
NotAllowedCursor = StandardCursor(0x0003600A)
|
||||||
)
|
)
|
||||||
|
@ -104,8 +104,12 @@ const (
|
|||||||
_OCR_CROSS = 32515
|
_OCR_CROSS = 32515
|
||||||
_OCR_HAND = 32649
|
_OCR_HAND = 32649
|
||||||
_OCR_IBEAM = 32513
|
_OCR_IBEAM = 32513
|
||||||
|
_OCR_NO = 32648
|
||||||
_OCR_NORMAL = 32512
|
_OCR_NORMAL = 32512
|
||||||
|
_OCR_SIZEALL = 32646
|
||||||
|
_OCR_SIZENESW = 32643
|
||||||
_OCR_SIZENS = 32645
|
_OCR_SIZENS = 32645
|
||||||
|
_OCR_SIZENWSE = 32642
|
||||||
_OCR_SIZEWE = 32644
|
_OCR_SIZEWE = 32644
|
||||||
_PM_NOREMOVE = 0x0000
|
_PM_NOREMOVE = 0x0000
|
||||||
_PM_REMOVE = 0x0001
|
_PM_REMOVE = 0x0001
|
||||||
|
@ -289,6 +289,12 @@ const (
|
|||||||
HandCursor StandardCursor = 0x00036004
|
HandCursor StandardCursor = 0x00036004
|
||||||
HResizeCursor StandardCursor = 0x00036005
|
HResizeCursor StandardCursor = 0x00036005
|
||||||
VResizeCursor StandardCursor = 0x00036006
|
VResizeCursor StandardCursor = 0x00036006
|
||||||
|
|
||||||
|
// v3.4
|
||||||
|
ResizeNWSECursor StandardCursor = 0x00036007
|
||||||
|
ResizeNESWCursor StandardCursor = 0x00036008
|
||||||
|
ResizeAllCursor StandardCursor = 0x00036009
|
||||||
|
NotAllowedCursor StandardCursor = 0x0003600A
|
||||||
)
|
)
|
||||||
|
|
||||||
type Error int
|
type Error int
|
||||||
|
@ -351,7 +351,11 @@ func CreateStandardCursor(shape StandardCursor) (*Cursor, error) {
|
|||||||
shape != CrosshairCursor &&
|
shape != CrosshairCursor &&
|
||||||
shape != HandCursor &&
|
shape != HandCursor &&
|
||||||
shape != HResizeCursor &&
|
shape != HResizeCursor &&
|
||||||
shape != VResizeCursor {
|
shape != VResizeCursor &&
|
||||||
|
shape != ResizeNWSECursor &&
|
||||||
|
shape != ResizeNESWCursor &&
|
||||||
|
shape != ResizeAllCursor &&
|
||||||
|
shape != NotAllowedCursor {
|
||||||
return nil, fmt.Errorf("goglfw: invalid standard cursor 0x%08X: %w", shape, InvalidEnum)
|
return nil, fmt.Errorf("goglfw: invalid standard cursor 0x%08X: %w", shape, InvalidEnum)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2242,6 +2242,14 @@ func (c *Cursor) platformCreateStandardCursor(shape StandardCursor) error {
|
|||||||
id = _OCR_SIZEWE
|
id = _OCR_SIZEWE
|
||||||
case VResizeCursor:
|
case VResizeCursor:
|
||||||
id = _OCR_SIZENS
|
id = _OCR_SIZENS
|
||||||
|
case ResizeNWSECursor: // v3.4
|
||||||
|
id = _OCR_SIZENWSE
|
||||||
|
case ResizeNESWCursor: // v3.4
|
||||||
|
id = _OCR_SIZENESW
|
||||||
|
case ResizeAllCursor: // v3.4
|
||||||
|
id = _OCR_SIZEALL
|
||||||
|
case NotAllowedCursor: // v3.4
|
||||||
|
id = _OCR_NO
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("goglfw: invalid shape: %d", shape)
|
return fmt.Errorf("goglfw: invalid shape: %d", shape)
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,10 @@ const (
|
|||||||
CursorShapePointer
|
CursorShapePointer
|
||||||
CursorShapeEWResize
|
CursorShapeEWResize
|
||||||
CursorShapeNSResize
|
CursorShapeNSResize
|
||||||
|
CursorShapeNESWResize
|
||||||
|
CursorShapeNWSEResize
|
||||||
|
CursorShapeMove
|
||||||
|
CursorShapeNotAllowed
|
||||||
)
|
)
|
||||||
|
|
||||||
type WindowResizingMode int
|
type WindowResizingMode int
|
||||||
|
@ -201,6 +201,10 @@ func initialize() error {
|
|||||||
glfwSystemCursors[CursorShapePointer] = glfw.CreateStandardCursor(glfw.HandCursor)
|
glfwSystemCursors[CursorShapePointer] = glfw.CreateStandardCursor(glfw.HandCursor)
|
||||||
glfwSystemCursors[CursorShapeEWResize] = glfw.CreateStandardCursor(glfw.HResizeCursor)
|
glfwSystemCursors[CursorShapeEWResize] = glfw.CreateStandardCursor(glfw.HResizeCursor)
|
||||||
glfwSystemCursors[CursorShapeNSResize] = glfw.CreateStandardCursor(glfw.VResizeCursor)
|
glfwSystemCursors[CursorShapeNSResize] = glfw.CreateStandardCursor(glfw.VResizeCursor)
|
||||||
|
glfwSystemCursors[CursorShapeNESWResize] = glfw.CreateStandardCursor(glfw.ResizeNESWCursor)
|
||||||
|
glfwSystemCursors[CursorShapeNWSEResize] = glfw.CreateStandardCursor(glfw.ResizeNWSECursor)
|
||||||
|
glfwSystemCursors[CursorShapeMove] = glfw.CreateStandardCursor(glfw.ResizeAllCursor)
|
||||||
|
glfwSystemCursors[CursorShapeNotAllowed] = glfw.CreateStandardCursor(glfw.NotAllowedCursor)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -614,7 +618,7 @@ func (u *userInterfaceImpl) SetCursorMode(mode CursorMode) {
|
|||||||
u.mainThread.Call(func() {
|
u.mainThread.Call(func() {
|
||||||
u.window.SetInputMode(glfw.CursorMode, driverCursorModeToGLFWCursorMode(mode))
|
u.window.SetInputMode(glfw.CursorMode, driverCursorModeToGLFWCursorMode(mode))
|
||||||
if mode == CursorModeVisible {
|
if mode == CursorModeVisible {
|
||||||
u.setNativeCursor(u.getCursorShape())
|
u.window.SetCursor(glfwSystemCursors[u.getCursorShape()])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -632,7 +636,7 @@ func (u *userInterfaceImpl) SetCursorShape(shape CursorShape) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
u.mainThread.Call(func() {
|
u.mainThread.Call(func() {
|
||||||
u.setNativeCursor(shape)
|
u.window.SetCursor(glfwSystemCursors[shape])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,17 +218,13 @@ var (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
sel_alloc = objc.RegisterName("alloc")
|
sel_alloc = objc.RegisterName("alloc")
|
||||||
sel_arrowCursor = objc.RegisterName("arrowCursor")
|
|
||||||
sel_class = objc.RegisterName("class")
|
sel_class = objc.RegisterName("class")
|
||||||
sel_collectionBehavior = objc.RegisterName("collectionBehavior")
|
sel_collectionBehavior = objc.RegisterName("collectionBehavior")
|
||||||
sel_crosshairCursor = objc.RegisterName("crosshairCursor")
|
|
||||||
sel_delegate = objc.RegisterName("delegate")
|
sel_delegate = objc.RegisterName("delegate")
|
||||||
sel_IBeamCursor = objc.RegisterName("IBeamCursor")
|
|
||||||
sel_init = objc.RegisterName("init")
|
sel_init = objc.RegisterName("init")
|
||||||
sel_initWithOrigDelegate = objc.RegisterName("initWithOrigDelegate:")
|
sel_initWithOrigDelegate = objc.RegisterName("initWithOrigDelegate:")
|
||||||
sel_mouseLocation = objc.RegisterName("mouseLocation")
|
sel_mouseLocation = objc.RegisterName("mouseLocation")
|
||||||
sel_performSelector = objc.RegisterName("performSelector:")
|
sel_performSelector = objc.RegisterName("performSelector:")
|
||||||
sel_pointingHandCursor = objc.RegisterName("pointingHandCursor")
|
|
||||||
sel_set = objc.RegisterName("set")
|
sel_set = objc.RegisterName("set")
|
||||||
sel_setCollectionBehavior = objc.RegisterName("setCollectionBehavior:")
|
sel_setCollectionBehavior = objc.RegisterName("setCollectionBehavior:")
|
||||||
sel_setDelegate = objc.RegisterName("setDelegate:")
|
sel_setDelegate = objc.RegisterName("setDelegate:")
|
||||||
@ -242,8 +238,6 @@ var (
|
|||||||
sel_windowDidResignKey = objc.RegisterName("windowDidResignKey:")
|
sel_windowDidResignKey = objc.RegisterName("windowDidResignKey:")
|
||||||
sel_windowDidResize = objc.RegisterName("windowDidResize:")
|
sel_windowDidResize = objc.RegisterName("windowDidResize:")
|
||||||
sel_windowDidChangeOcclusionState = objc.RegisterName("windowDidChangeOcclusionState:")
|
sel_windowDidChangeOcclusionState = objc.RegisterName("windowDidChangeOcclusionState:")
|
||||||
sel_windowResizeEastWestCursor = objc.RegisterName("_windowResizeEastWestCursor")
|
|
||||||
sel_windowResizeNorthSouthCursor = objc.RegisterName("_windowResizeNorthSouthCursor")
|
|
||||||
sel_windowShouldClose = objc.RegisterName("windowShouldClose:")
|
sel_windowShouldClose = objc.RegisterName("windowShouldClose:")
|
||||||
sel_windowWillEnterFullScreen = objc.RegisterName("windowWillEnterFullScreen:")
|
sel_windowWillEnterFullScreen = objc.RegisterName("windowWillEnterFullScreen:")
|
||||||
sel_windowWillExitFullScreen = objc.RegisterName("windowWillExitFullScreen:")
|
sel_windowWillExitFullScreen = objc.RegisterName("windowWillExitFullScreen:")
|
||||||
@ -303,26 +297,6 @@ func (u *userInterfaceImpl) isNativeFullscreen() bool {
|
|||||||
return cocoa.NSWindow{ID: objc.ID(u.window.GetCocoaWindow())}.StyleMask()&cocoa.NSWindowStyleMaskFullScreen != 0
|
return cocoa.NSWindow{ID: objc.ID(u.window.GetCocoaWindow())}.StyleMask()&cocoa.NSWindowStyleMaskFullScreen != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *userInterfaceImpl) setNativeCursor(shape CursorShape) {
|
|
||||||
NSCursor := objc.ID(class_NSCursor).Send(sel_class)
|
|
||||||
cursor := NSCursor.Send(sel_performSelector, sel_arrowCursor)
|
|
||||||
switch shape {
|
|
||||||
case 0:
|
|
||||||
cursor = NSCursor.Send(sel_performSelector, sel_arrowCursor)
|
|
||||||
case 1:
|
|
||||||
cursor = NSCursor.Send(sel_performSelector, sel_IBeamCursor)
|
|
||||||
case 2:
|
|
||||||
cursor = NSCursor.Send(sel_performSelector, sel_crosshairCursor)
|
|
||||||
case 3:
|
|
||||||
cursor = NSCursor.Send(sel_performSelector, sel_pointingHandCursor)
|
|
||||||
case 4:
|
|
||||||
cursor = NSCursor.Send(sel_performSelector, sel_windowResizeEastWestCursor)
|
|
||||||
case 5:
|
|
||||||
cursor = NSCursor.Send(sel_performSelector, sel_windowResizeNorthSouthCursor)
|
|
||||||
}
|
|
||||||
cursor.Send(sel_set)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *userInterfaceImpl) isNativeFullscreenAvailable() bool {
|
func (u *userInterfaceImpl) isNativeFullscreenAvailable() bool {
|
||||||
// TODO: If the window is transparent, we should use GLFW's windowed fullscreen (#1822, #1857).
|
// TODO: If the window is transparent, we should use GLFW's windowed fullscreen (#1822, #1857).
|
||||||
// However, if the user clicks the green button, should this window be in native fullscreen mode?
|
// However, if the user clicks the green button, should this window be in native fullscreen mode?
|
||||||
|
@ -200,11 +200,6 @@ func (u *userInterfaceImpl) isNativeFullscreen() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *userInterfaceImpl) setNativeCursor(shape CursorShape) {
|
|
||||||
// TODO: Use native API in the future (#1571)
|
|
||||||
u.window.SetCursor(glfwSystemCursors[shape])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *userInterfaceImpl) isNativeFullscreenAvailable() bool {
|
func (u *userInterfaceImpl) isNativeFullscreenAvailable() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -189,11 +189,6 @@ func (u *userInterfaceImpl) isNativeFullscreen() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *userInterfaceImpl) setNativeCursor(shape CursorShape) {
|
|
||||||
// TODO: Use native API in the future (#1571)
|
|
||||||
u.window.SetCursor(glfwSystemCursors[shape])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *userInterfaceImpl) isNativeFullscreenAvailable() bool {
|
func (u *userInterfaceImpl) isNativeFullscreenAvailable() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,14 @@ func driverCursorShapeToCSSCursor(cursor CursorShape) string {
|
|||||||
return "ew-resize"
|
return "ew-resize"
|
||||||
case CursorShapeNSResize:
|
case CursorShapeNSResize:
|
||||||
return "ns-resize"
|
return "ns-resize"
|
||||||
|
case CursorShapeNESWResize:
|
||||||
|
return "nesw-resize"
|
||||||
|
case CursorShapeNWSEResize:
|
||||||
|
return "nwse-resize"
|
||||||
|
case CursorShapeMove:
|
||||||
|
return "move"
|
||||||
|
case CursorShapeNotAllowed:
|
||||||
|
return "not-allowed"
|
||||||
}
|
}
|
||||||
return "auto"
|
return "auto"
|
||||||
}
|
}
|
||||||
|
2
run.go
2
run.go
@ -378,6 +378,8 @@ func CursorShape() CursorShapeType {
|
|||||||
|
|
||||||
// SetCursorShape sets the cursor shape.
|
// SetCursorShape sets the cursor shape.
|
||||||
//
|
//
|
||||||
|
// If the platform doesn't implement the given shape, the default cursor shape is used.
|
||||||
|
//
|
||||||
// SetCursorShape is concurrent-safe.
|
// SetCursorShape is concurrent-safe.
|
||||||
func SetCursorShape(shape CursorShapeType) {
|
func SetCursorShape(shape CursorShapeType) {
|
||||||
ui.Get().SetCursorShape(shape)
|
ui.Get().SetCursorShape(shape)
|
||||||
|
Loading…
Reference in New Issue
Block a user