Wayland: Add support for animated standard cursors

This commit is contained in:
Emmanuel Gil Peyrot 2018-09-08 20:05:40 +02:00 committed by linkmauve
parent dede6d6886
commit 5ea6e6cda2
3 changed files with 71 additions and 36 deletions

View File

@ -137,6 +137,7 @@ static void setCursor(const char* name)
"Wayland: Standard cursor not found"); "Wayland: Standard cursor not found");
return; return;
} }
// TODO: handle animated cursors too.
image = cursor->images[0]; image = cursor->images[0];
if (!image) if (!image)

View File

@ -333,10 +333,11 @@ typedef struct _GLFWmonitorWayland
// //
typedef struct _GLFWcursorWayland typedef struct _GLFWcursorWayland
{ {
struct wl_cursor_image* image; struct wl_cursor* cursor;
struct wl_buffer* buffer; struct wl_buffer* buffer;
int width, height; int width, height;
int xhot, yhot; int xhot, yhot;
int currentImage;
} _GLFWcursorWayland; } _GLFWcursorWayland;

View File

@ -690,6 +690,60 @@ static GLFWbool createXdgSurface(_GLFWwindow* window)
return GLFW_TRUE; return GLFW_TRUE;
} }
static void
setCursorImage(_GLFWcursorWayland* cursorWayland)
{
struct itimerspec timer = {};
struct wl_cursor_image* image;
struct wl_buffer* buffer;
struct wl_surface* surface = _glfw.wl.cursorSurface;
if (!cursorWayland->cursor)
buffer = cursorWayland->buffer;
else
{
image = cursorWayland->cursor->images[cursorWayland->currentImage];
buffer = wl_cursor_image_get_buffer(image);
if (!buffer)
return;
timer.it_value.tv_sec = image->delay / 1000;
timer.it_value.tv_nsec = (image->delay % 1000) * 1000000;
timerfd_settime(_glfw.wl.cursorTimerfd, 0, &timer, NULL);
cursorWayland->width = image->width;
cursorWayland->height = image->height;
cursorWayland->xhot = image->hotspot_x;
cursorWayland->yhot = image->hotspot_y;
}
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
surface,
cursorWayland->xhot,
cursorWayland->yhot);
wl_surface_attach(surface, buffer, 0, 0);
wl_surface_damage(surface, 0, 0,
cursorWayland->width, cursorWayland->height);
wl_surface_commit(surface);
}
static void
incrementCursorImage(_GLFWwindow* window)
{
_GLFWcursor* cursor;
if (!window || window->wl.decorations.focus != mainWindow)
return;
cursor = window->wl.currentCursor;
if (cursor && cursor->wl.cursor)
{
cursor->wl.currentImage += 1;
cursor->wl.currentImage %= cursor->wl.cursor->image_count;
setCursorImage(&cursor->wl);
}
}
static void static void
handleEvents(int timeout) handleEvents(int timeout)
{ {
@ -750,7 +804,7 @@ handleEvents(int timeout)
if (read_ret != 8) if (read_ret != 8)
return; return;
// TODO: implement! incrementCursorImage(_glfw.wl.pointerFocus);
} }
} }
else else
@ -1267,14 +1321,15 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
return GLFW_FALSE; return GLFW_FALSE;
} }
cursor->wl.image = standardCursor->images[0]; cursor->wl.cursor = standardCursor;
cursor->wl.currentImage = 0;
return GLFW_TRUE; return GLFW_TRUE;
} }
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
{ {
// If it's a standard cursor we don't need to do anything here // If it's a standard cursor we don't need to do anything here
if (cursor->wl.image) if (cursor->wl.cursor)
return; return;
if (cursor->wl.buffer) if (cursor->wl.buffer)
@ -1380,10 +1435,7 @@ static GLFWbool isPointerLocked(_GLFWwindow* window)
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
{ {
struct wl_buffer* buffer;
struct wl_cursor* defaultCursor; struct wl_cursor* defaultCursor;
struct wl_cursor_image* image;
struct wl_surface* surface = _glfw.wl.cursorSurface;
if (!_glfw.wl.pointer) if (!_glfw.wl.pointer)
return; return;
@ -1392,7 +1444,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
// If we're not in the correct window just save the cursor // If we're not in the correct window just save the cursor
// the next time the pointer enters the window the cursor will change // the next time the pointer enters the window the cursor will change
if (window != _glfw.wl.pointerFocus) if (window != _glfw.wl.pointerFocus || window->wl.decorations.focus != mainWindow)
return; return;
// Unlock possible pointer lock if no longer disabled. // Unlock possible pointer lock if no longer disabled.
@ -1402,7 +1454,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
if (window->cursorMode == GLFW_CURSOR_NORMAL) if (window->cursorMode == GLFW_CURSOR_NORMAL)
{ {
if (cursor) if (cursor)
image = cursor->wl.image; setCursorImage(&cursor->wl);
else else
{ {
defaultCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, defaultCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,
@ -1413,33 +1465,14 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
"Wayland: Standard cursor not found"); "Wayland: Standard cursor not found");
return; return;
} }
image = defaultCursor->images[0]; _GLFWcursorWayland cursorWayland = {
} defaultCursor,
NULL,
if (image) 0, 0,
{ 0, 0,
buffer = wl_cursor_image_get_buffer(image); 0
if (!buffer) };
return; setCursorImage(&cursorWayland);
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
surface,
image->hotspot_x,
image->hotspot_y);
wl_surface_attach(surface, buffer, 0, 0);
wl_surface_damage(surface, 0, 0,
image->width, image->height);
wl_surface_commit(surface);
}
else
{
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
surface,
cursor->wl.xhot,
cursor->wl.yhot);
wl_surface_attach(surface, cursor->wl.buffer, 0, 0);
wl_surface_damage(surface, 0, 0,
cursor->wl.width, cursor->wl.height);
wl_surface_commit(surface);
} }
} }
else if (window->cursorMode == GLFW_CURSOR_DISABLED) else if (window->cursorMode == GLFW_CURSOR_DISABLED)