Wayland: Add support for animated cursors

This commit is contained in:
Kovid Goyal 2018-09-10 11:54:22 +05:30
parent 141b8a1481
commit 0195e7f841
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 82 additions and 36 deletions

4
glfw/wl_init.c vendored
View File

@ -139,6 +139,7 @@ static void setCursor(const char* name)
"Wayland: Standard cursor not found");
return;
}
// TODO: handle animated cursors too.
image = cursor->images[0];
if (!image)
@ -688,7 +689,8 @@ int _glfwPlatformInit(void)
}
initPollData(&_glfw.wl.eventLoopData, _glfw.wl.eventLoopData.wakeupFds[0], wl_display_get_fd(_glfw.wl.display));
glfw_dbus_init(&_glfw.wl.dbus, &_glfw.wl.eventLoopData);
_glfw.wl.keyRepeatInfo.keyRepeatTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-keyrepeat", 0.5, 0, dispatchPendingKeyRepeats, NULL);
_glfw.wl.keyRepeatInfo.keyRepeatTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-key-repeat", 0.5, 0, dispatchPendingKeyRepeats, NULL);
_glfw.wl.cursorAnimationTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-cursor-animation", 0.5, 0, animateCursorImage, NULL);
_glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
wl_registry_add_listener(_glfw.wl.registry, &registryListener, NULL);

5
glfw/wl_platform.h vendored
View File

@ -225,6 +225,7 @@ typedef struct _GLFWlibraryWayland
id_type keyRepeatTimer;
_GLFWwindow* keyboardFocus;
} keyRepeatInfo;
id_type cursorAnimationTimer;
_GLFWXKBData xkb;
_GLFWDBUSData dbus;
@ -274,12 +275,14 @@ typedef struct _GLFWmonitorWayland
//
typedef struct _GLFWcursorWayland
{
struct wl_cursor_image* image;
struct wl_cursor* cursor;
struct wl_buffer* buffer;
int width, height;
int xhot, yhot;
int currentImage;
} _GLFWcursorWayland;
void _glfwAddOutputWayland(uint32_t name, uint32_t version);
void _glfwSetupWaylandDataDevice();
void animateCursorImage(id_type timer_id, void *data);

109
glfw/wl_window.c vendored
View File

@ -702,6 +702,68 @@ static GLFWbool createXdgSurface(_GLFWwindow* window)
return GLFW_TRUE;
}
static void
setCursorImage(_GLFWcursorWayland* cursorWayland)
{
struct wl_cursor_image* image;
struct wl_buffer* buffer;
struct wl_surface* surface = _glfw.wl.cursorSurface;
if (!cursorWayland->cursor) {
buffer = cursorWayland->buffer;
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 0);
} else
{
image = cursorWayland->cursor->images[cursorWayland->currentImage];
buffer = wl_cursor_image_get_buffer(image);
if (image->delay) {
changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, ((double)image->delay) / 1000.0);
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 1);
} else {
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 0);
}
if (!buffer)
return;
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)
{
if (window && window->wl.decorations.focus == mainWindow) {
_GLFWcursor* cursor = window->wl.currentCursor;
if (cursor && cursor->wl.cursor)
{
cursor->wl.currentImage += 1;
cursor->wl.currentImage %= cursor->wl.cursor->image_count;
setCursorImage(&cursor->wl);
return;
}
}
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 1);
}
void
animateCursorImage(id_type timer_id, void *data) {
incrementCursorImage(_glfw.wl.pointerFocus);
}
static void
handleEvents(double timeout)
{
@ -1263,14 +1325,15 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
return GLFW_FALSE;
}
cursor->wl.image = standardCursor->images[0];
cursor->wl.cursor = standardCursor;
cursor->wl.currentImage = 0;
return GLFW_TRUE;
}
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
{
// If it's a standard cursor we don't need to do anything here
if (cursor->wl.image)
if (cursor->wl.cursor)
return;
if (cursor->wl.buffer)
@ -1376,10 +1439,7 @@ static GLFWbool isPointerLocked(_GLFWwindow* window)
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
{
struct wl_buffer* buffer;
struct wl_cursor* defaultCursor;
struct wl_cursor_image* image;
struct wl_surface* surface = _glfw.wl.cursorSurface;
if (!_glfw.wl.pointer)
return;
@ -1388,7 +1448,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* 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
if (window != _glfw.wl.pointerFocus)
if (window != _glfw.wl.pointerFocus || window->wl.decorations.focus != mainWindow)
return;
// Unlock possible pointer lock if no longer disabled.
@ -1398,7 +1458,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
if (window->cursorMode == GLFW_CURSOR_NORMAL)
{
if (cursor)
image = cursor->wl.image;
setCursorImage(&cursor->wl);
else
{
defaultCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,
@ -1409,33 +1469,14 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
"Wayland: Standard cursor not found");
return;
}
image = defaultCursor->images[0];
}
if (image)
{
buffer = wl_cursor_image_get_buffer(image);
if (!buffer)
return;
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);
_GLFWcursorWayland cursorWayland = {
defaultCursor,
NULL,
0, 0,
0, 0,
0
};
setCursorImage(&cursorWayland);
}
}
else if (window->cursorMode == GLFW_CURSOR_DISABLED)