diff --git a/Makefile.common b/Makefile.common index bbcc702598..8245497b45 100644 --- a/Makefile.common +++ b/Makefile.common @@ -580,8 +580,8 @@ endif ifeq ($(HAVE_WAYLAND), 1) OBJ += gfx/drivers_context/wayland_ctx.o - DEFINES += $(WAYLAND_CFLAGS) - LIBS += $(WAYLAND_LIBS) + DEFINES += $(WAYLAND_CFLAGS) $(WAYLAND_CURSOR_CFLAGS) + LIBS += $(WAYLAND_LIBS) $(WAYLAND_CURSOR_LIBS) endif #Input diff --git a/gfx/drivers_context/wayland_ctx.c b/gfx/drivers_context/wayland_ctx.c index 046e8fd187..d5e231e23a 100644 --- a/gfx/drivers_context/wayland_ctx.c +++ b/gfx/drivers_context/wayland_ctx.c @@ -18,6 +18,7 @@ #include #include +#include #include @@ -70,6 +71,7 @@ typedef struct gfx_ctx_wayland_data struct wl_keyboard *wl_keyboard; struct wl_pointer *wl_pointer; struct wl_seat *seat; + struct wl_shm *shm; unsigned swap_interval; bool core_hw_context_enable; @@ -89,6 +91,16 @@ typedef struct gfx_ctx_wayland_data bool focus; bool left, right, middle; } mouse; + + struct + { + struct wl_cursor *default_cursor; + struct wl_cursor_theme *theme; + struct wl_surface *surface; + uint32_t serial; + bool visible; + } cursor; + const input_device_driver_t *joypad; bool blocked; @@ -215,6 +227,7 @@ static void keyboard_handle_repeat_info(void *data, (void)wl_keyboard; (void)rate; (void)delay; + /* TODO: Seems like we'll need this to get repeat working. We'll have to do it on our own. */ } static const struct wl_keyboard_listener keyboard_listener = { @@ -226,6 +239,8 @@ static const struct wl_keyboard_listener keyboard_listener = { keyboard_handle_repeat_info, }; +static void gfx_ctx_wl_show_mouse(void *data, bool state); + static void pointer_handle_enter(void *data, struct wl_pointer *pointer, uint32_t serial, @@ -243,6 +258,9 @@ static void pointer_handle_enter(void *data, wl->mouse.x = wl->mouse.last_x; wl->mouse.y = wl->mouse.last_y; wl->mouse.focus = true; + wl->cursor.serial = serial; + + gfx_ctx_wl_show_mouse(data, wl->cursor.visible); } static void pointer_handle_leave(void *data, @@ -492,6 +510,8 @@ static void registry_handle_global(void *data, struct wl_registry *reg, else if (string_is_equal(interface, "wl_shell")) wl->shell = (struct wl_shell*) wl_registry_bind(reg, id, &wl_shell_interface, 1); + else if (string_is_equal(interface, "wl_shm")) + wl->shm = wl_registry_bind(reg, id, &wl_shm_interface, 1); else if (string_is_equal(interface, "wl_seat")) { wl->seat = wl_registry_bind(reg, id, &wl_seat_interface, 4); @@ -560,6 +580,11 @@ static void gfx_ctx_wl_destroy_resources(gfx_ctx_wayland_data_t *wl) if (wl->wl_pointer) wl_pointer_destroy(wl->wl_pointer); + if (wl->cursor.theme) + wl_cursor_theme_destroy(wl->cursor.theme); + if (wl->cursor.surface) + wl_surface_destroy(wl->cursor.surface); + if (wl->seat) wl_seat_destroy(wl->seat); if (wl->shell) @@ -862,6 +887,12 @@ static void *gfx_ctx_wl_init(void *video_driver) goto error; } + if (!wl->shm) + { + RARCH_ERR("Failed to create shm.\n"); + goto error; + } + if (!wl->shell) { RARCH_ERR("Failed to create shell.\n"); @@ -902,6 +933,11 @@ static void *gfx_ctx_wl_init(void *video_driver) wl->keyboard_focus = true; wl->mouse.focus = true; + wl->cursor.surface = wl_compositor_create_surface(wl->compositor); + wl->cursor.theme = wl_cursor_theme_load(NULL, 16, wl->shm); + wl->cursor.default_cursor = wl_cursor_theme_get_cursor(wl->cursor.theme, "left_ptr"); + flush_wayland_fd(wl); + return wl; error: @@ -1123,6 +1159,14 @@ static bool gfx_ctx_wl_set_video_mode(void *data, break; } + if (fullscreen) + { + wl->cursor.visible = false; + gfx_ctx_wl_show_mouse(wl, false); + } + else + wl->cursor.visible = true; + return true; error: @@ -1592,6 +1636,26 @@ static void gfx_ctx_wl_set_flags(void *data, uint32_t flags) wl->core_hw_context_enable = true; } +static void gfx_ctx_wl_show_mouse(void *data, bool state) +{ + gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; + if (!wl->wl_pointer) + return; + + if (state) + { + struct wl_cursor_image *image = wl->cursor.default_cursor->images[0]; + wl_pointer_set_cursor(wl->wl_pointer, wl->cursor.serial, wl->cursor.surface, image->hotspot_x, image->hotspot_y); + wl_surface_attach(wl->cursor.surface, wl_cursor_image_get_buffer(image), 0, 0); + wl_surface_damage(wl->cursor.surface, 0, 0, image->width, image->height); + wl_surface_commit(wl->cursor.surface); + } + else + wl_pointer_set_cursor(wl->wl_pointer, wl->cursor.serial, NULL, 0, 0); + + wl->cursor.visible = state; +} + const gfx_ctx_driver_t gfx_ctx_wayland = { gfx_ctx_wl_init, gfx_ctx_wl_destroy, @@ -1615,7 +1679,7 @@ const gfx_ctx_driver_t gfx_ctx_wayland = { gfx_ctx_wl_get_proc_address, NULL, NULL, - NULL, + gfx_ctx_wl_show_mouse, "wayland", gfx_ctx_wl_get_flags, gfx_ctx_wl_set_flags, @@ -1625,5 +1689,5 @@ const gfx_ctx_driver_t gfx_ctx_wayland = { #else NULL, #endif - NULL + NULL, }; diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 850a2b36e9..c151f6b1e1 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -395,6 +395,7 @@ check_pkgconf XCB xcb [ "$HAVE_X11" = "no" ] && HAVE_XEXT=no && HAVE_XF86VM=no && HAVE_XINERAMA=no && HAVE_XSHM=no check_pkgconf WAYLAND wayland-egl +check_pkgconf WAYLAND_CURSOR wayland-cursor check_pkgconf XKBCOMMON xkbcommon 0.3.2 check_pkgconf DBUS dbus-1 @@ -483,6 +484,6 @@ fi # Creates config.mk and config.h. add_define_make GLOBAL_CONFIG_DIR "$GLOBAL_CONFIG_DIR" -VARS=$(eval set | grep ^HAVE_ | sed s/=.*// | sed s/^HAVE_//) +VARS="$(eval set | grep ^HAVE_ | sed s/=.*// | sed s/^HAVE_//) WAYLAND_CURSOR" create_config_make config.mk $VARS create_config_header config.h $VARS