Cleanup: move internal Wayland cursor API's into their own doxy section

Also resolve building when USE_EVENT_BACKGROUND_THREAD is disabled.
This commit is contained in:
Campbell Barton 2023-12-13 09:55:02 +11:00
parent 224658266f
commit 46a9530a75
2 changed files with 331 additions and 301 deletions

@ -120,6 +120,11 @@ static void gwl_seat_capability_pointer_disable(GWL_Seat *seat);
static void gwl_seat_capability_keyboard_disable(GWL_Seat *seat);
static void gwl_seat_capability_touch_disable(GWL_Seat *seat);
static void gwl_seat_cursor_anim_begin(GWL_Seat *seat);
static void gwl_seat_cursor_anim_begin_if_needed(GWL_Seat *seat);
static void gwl_seat_cursor_anim_end(GWL_Seat *seat);
static void gwl_seat_cursor_anim_reset(GWL_Seat *seat);
static bool gwl_registry_entry_remove_by_name(GWL_Display *display,
uint32_t name,
int *r_interface_slot);
@ -135,11 +140,6 @@ static void gwl_display_event_thread_destroy(GWL_Display *display);
static void ghost_wl_display_lock_without_input(wl_display *wl_display, std::mutex *server_mutex);
static void cursor_anim_begin_if_needed(GWL_Seat *seat);
static void cursor_anim_begin(GWL_Seat *seat);
static void cursor_anim_end(GWL_Seat *seat);
static void cursor_anim_reset(GWL_Seat *seat);
/** Default size for pending event vector. */
constexpr size_t events_pending_default_size = 4096 / sizeof(void *);
@ -1336,7 +1336,7 @@ static void gwl_display_destroy(GWL_Display *display)
/* Stop all animated cursors (freeing their #GWL_Cursor_AnimHandle). */
for (GWL_Seat *seat : display->seats) {
cursor_anim_end(seat);
gwl_seat_cursor_anim_end(seat);
}
/* For typical WAYLAND use this will always be set.
@ -2026,6 +2026,7 @@ static const char *ghost_wl_mime_send[] = {
"text/plain",
};
#ifdef USE_EVENT_BACKGROUND_THREAD
static void pthread_set_min_priority(pthread_t handle)
{
int policy;
@ -2046,6 +2047,7 @@ static void thread_set_min_priority(std::thread &thread)
* This cast might be avoided with clever template use. */
pthread_set_min_priority(reinterpret_cast<pthread_t>(thread.native_handle()));
}
#endif /* USE_EVENT_BACKGROUND_THREAD */
static int memfd_create_sealed(const char *name)
{
@ -2383,6 +2385,321 @@ static char *read_file_as_buffer(const int fd, const bool nil_terminate, size_t
/** \} */
/* -------------------------------------------------------------------- */
/** \name Private Cursor API
* \{ */
static void cursor_buffer_set_surface_impl(const wl_cursor_image *wl_image,
wl_buffer *buffer,
wl_surface *wl_surface,
const int scale)
{
const int32_t image_size_x = int32_t(wl_image->width);
const int32_t image_size_y = int32_t(wl_image->height);
GHOST_ASSERT((image_size_x % scale) == 0 && (image_size_y % scale) == 0,
"The size must be a multiple of the scale!");
wl_surface_set_buffer_scale(wl_surface, scale);
wl_surface_attach(wl_surface, buffer, 0, 0);
wl_surface_damage(wl_surface, 0, 0, image_size_x, image_size_y);
wl_surface_commit(wl_surface);
}
/**
* Needed to ensure the cursor size is always a multiple of scale.
*/
static int cursor_buffer_compatible_scale_from_image(const wl_cursor_image *wl_image, int scale)
{
const int32_t image_size_x = int32_t(wl_image->width);
const int32_t image_size_y = int32_t(wl_image->height);
while (scale > 1) {
if ((image_size_x % scale) == 0 && (image_size_y % scale) == 0) {
break;
}
scale -= 1;
}
return scale;
}
static const wl_cursor *gwl_seat_cursor_find_from_shape(GWL_Seat *seat,
const GHOST_TStandardCursor shape,
const char **r_cursor_name)
{
/* Caller must lock `server_mutex`. */
GWL_Cursor *cursor = &seat->cursor;
wl_cursor *wl_cursor = nullptr;
const char *cursor_name = ghost_wl_cursors.names[shape];
if (cursor_name[0] != '\0') {
if (!cursor->wl.theme) {
/* The cursor wl_surface hasn't entered an output yet. Initialize theme with scale 1. */
cursor->wl.theme = wl_cursor_theme_load(
cursor->theme_name.c_str(), cursor->theme_size, seat->system->wl_shm_get());
}
if (cursor->wl.theme) {
wl_cursor = wl_cursor_theme_get_cursor(cursor->wl.theme, cursor_name);
if (!wl_cursor) {
GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl);
}
}
}
if (r_cursor_name && wl_cursor) {
*r_cursor_name = cursor_name;
}
return wl_cursor;
}
/**
* Show the buffer defined by #gwl_seat_cursor_buffer_set without changing anything else,
* so #gwl_seat_cursor_buffer_hide can be used to display it again.
*
* The caller is responsible for setting `seat->cursor.visible`.
*/
static void gwl_seat_cursor_buffer_show(GWL_Seat *seat)
{
const GWL_Cursor *cursor = &seat->cursor;
if (seat->wl.pointer) {
const int scale = cursor->is_custom ? cursor->custom_scale : seat->pointer.theme_scale;
const int32_t hotspot_x = int32_t(cursor->wl.image.hotspot_x) / scale;
const int32_t hotspot_y = int32_t(cursor->wl.image.hotspot_y) / scale;
wl_pointer_set_cursor(
seat->wl.pointer, seat->pointer.serial, cursor->wl.surface_cursor, hotspot_x, hotspot_y);
}
if (!seat->wp.tablet_tools.empty()) {
const int scale = cursor->is_custom ? cursor->custom_scale : seat->tablet.theme_scale;
const int32_t hotspot_x = int32_t(cursor->wl.image.hotspot_x) / scale;
const int32_t hotspot_y = int32_t(cursor->wl.image.hotspot_y) / scale;
for (zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->wp.tablet_tools) {
GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(
zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2));
zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2,
seat->tablet.serial,
tablet_tool->wl.surface_cursor,
hotspot_x,
hotspot_y);
#ifdef USE_KDE_TABLET_HIDDEN_CURSOR_HACK
wl_surface_commit(tablet_tool->wl.surface_cursor);
#endif
}
}
gwl_seat_cursor_anim_reset(seat);
}
/**
* Hide the buffer defined by #gwl_seat_cursor_buffer_set without changing anything else,
* so #gwl_seat_cursor_buffer_show can be used to display it again.
*
* The caller is responsible for setting `seat->cursor.visible`.
*/
static void gwl_seat_cursor_buffer_hide(GWL_Seat *seat)
{
gwl_seat_cursor_anim_end(seat);
wl_pointer_set_cursor(seat->wl.pointer, seat->pointer.serial, nullptr, 0, 0);
for (zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->wp.tablet_tools) {
zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2, seat->tablet.serial, nullptr, 0, 0);
}
}
static void gwl_seat_cursor_buffer_set(const GWL_Seat *seat,
const wl_cursor_image *wl_image,
wl_buffer *buffer)
{
const GWL_Cursor *cursor = &seat->cursor;
const bool visible = (cursor->visible && cursor->is_hardware);
/* This is a requirement of WAYLAND, when this isn't the case,
* it causes Blender's window to close intermittently. */
if (seat->wl.pointer) {
const int scale = cursor_buffer_compatible_scale_from_image(
wl_image, cursor->is_custom ? cursor->custom_scale : seat->pointer.theme_scale);
const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale;
const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale;
cursor_buffer_set_surface_impl(wl_image, buffer, cursor->wl.surface_cursor, scale);
wl_pointer_set_cursor(seat->wl.pointer,
seat->pointer.serial,
visible ? cursor->wl.surface_cursor : nullptr,
hotspot_x,
hotspot_y);
}
/* Set the cursor for all tablet tools as well. */
if (!seat->wp.tablet_tools.empty()) {
const int scale = cursor_buffer_compatible_scale_from_image(
wl_image, cursor->is_custom ? cursor->custom_scale : seat->tablet.theme_scale);
const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale;
const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale;
for (zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->wp.tablet_tools) {
GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(
zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2));
cursor_buffer_set_surface_impl(wl_image, buffer, tablet_tool->wl.surface_cursor, scale);
zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2,
seat->tablet.serial,
visible ? tablet_tool->wl.surface_cursor : nullptr,
hotspot_x,
hotspot_y);
}
}
}
static void gwl_seat_cursor_buffer_set_current(GWL_Seat *seat)
{
const GWL_Cursor *cursor = &seat->cursor;
gwl_seat_cursor_anim_end(seat);
gwl_seat_cursor_buffer_set(seat, &cursor->wl.image, cursor->wl.buffer);
gwl_seat_cursor_anim_begin_if_needed(seat);
}
enum eCursorSetMode {
CURSOR_VISIBLE_ALWAYS_SET = 1,
CURSOR_VISIBLE_ONLY_HIDE,
CURSOR_VISIBLE_ONLY_SHOW,
};
static void gwl_seat_cursor_visible_set(GWL_Seat *seat,
const bool visible,
const bool is_hardware,
const enum eCursorSetMode set_mode)
{
GWL_Cursor *cursor = &seat->cursor;
const bool was_visible = cursor->is_hardware && cursor->visible;
const bool use_visible = is_hardware && visible;
if (set_mode == CURSOR_VISIBLE_ALWAYS_SET) {
/* Pass. */
}
else if (set_mode == CURSOR_VISIBLE_ONLY_SHOW) {
if (!use_visible) {
return;
}
}
else if (set_mode == CURSOR_VISIBLE_ONLY_HIDE) {
if (use_visible) {
return;
}
}
if (use_visible) {
if (!was_visible) {
gwl_seat_cursor_buffer_show(seat);
}
}
else {
if (was_visible) {
gwl_seat_cursor_buffer_hide(seat);
}
}
cursor->visible = visible;
cursor->is_hardware = is_hardware;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Private Cursor Animation API
* \{ */
#ifdef USE_EVENT_BACKGROUND_THREAD
static bool gwl_seat_cursor_anim_check(GWL_Seat *seat)
{
const wl_cursor *wl_cursor = seat->cursor.wl.theme_cursor;
if (!wl_cursor) {
return false;
}
/* NOTE: return true to stress test animated cursor,
* to ensure (otherwise rare) issues are triggered more frequently. */
// return true;
return wl_cursor->image_count > 1;
}
static void gwl_seat_cursor_anim_begin(GWL_Seat *seat)
{
/* Caller must lock `server_mutex`. */
GHOST_ASSERT(seat->cursor.anim_handle == nullptr, "Must be cleared");
/* Callback for updating the cursor animation. */
auto cursor_anim_frame_step_fn =
[](GWL_Seat *seat, GWL_Cursor_AnimHandle *anim_handle, int delay) {
/* It's possible the `wl_cursor` is reloaded while the cursor is animating.
* Don't access outside the lock, that's why the `delay` is passed in. */
std::mutex *server_mutex = seat->system->server_mutex;
int frame = 0;
while (!anim_handle->exit_pending.load()) {
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
if (!anim_handle->exit_pending.load()) {
std::lock_guard lock_server_guard{*server_mutex};
if (!anim_handle->exit_pending.load()) {
const struct wl_cursor *wl_cursor = seat->cursor.wl.theme_cursor;
frame = (frame + 1) % wl_cursor->image_count;
wl_cursor_image *image = wl_cursor->images[frame];
wl_buffer *buffer = wl_cursor_image_get_buffer(image);
gwl_seat_cursor_buffer_set(seat, image, buffer);
delay = wl_cursor->images[frame]->delay;
/* Without this the cursor won't update when other processes are occupied. */
wl_display_flush(seat->system->wl_display_get());
}
}
}
delete anim_handle;
};
/* Allocate so this can be set before the thread begins. */
GWL_Cursor_AnimHandle *anim_handle = new GWL_Cursor_AnimHandle;
seat->cursor.anim_handle = anim_handle;
const int delay = seat->cursor.wl.theme_cursor->images[0]->delay;
std::thread cursor_anim_thread(cursor_anim_frame_step_fn, seat, anim_handle, delay);
/* Application logic should take priority. */
thread_set_min_priority(cursor_anim_thread);
cursor_anim_thread.detach();
}
static void gwl_seat_cursor_anim_begin_if_needed(GWL_Seat *seat)
{
if (gwl_seat_cursor_anim_check(seat)) {
gwl_seat_cursor_anim_begin(seat);
}
}
static void gwl_seat_cursor_anim_end(GWL_Seat *seat)
{
GWL_Cursor *cursor = &seat->cursor;
if (cursor->anim_handle) {
GWL_Cursor_AnimHandle *anim_handle = cursor->anim_handle;
cursor->anim_handle = nullptr;
anim_handle->exit_pending.store(true);
}
}
static void gwl_seat_cursor_anim_reset(GWL_Seat *seat)
{
gwl_seat_cursor_anim_end(seat);
gwl_seat_cursor_anim_begin_if_needed(seat);
}
#else
/* Unfortunately cursor animation requires a background thread. */
[[maybe_unused]] static bool gwl_seat_cursor_anim_check(GWL_Seat * /*seat*/)
{
return false;
}
[[maybe_unused]] static void gwl_seat_cursor_anim_begin(GWL_Seat * /*seat*/) {}
[[maybe_unused]] static void gwl_seat_cursor_anim_begin_if_needed(GWL_Seat * /*seat*/) {}
[[maybe_unused]] static void gwl_seat_cursor_anim_end(GWL_Seat * /*seat*/) {}
[[maybe_unused]] static void gwl_seat_cursor_anim_reset(GWL_Seat * /*seat*/) {}
#endif /* !USE_EVENT_BACKGROUND_THREAD */
/** \} */
/* -------------------------------------------------------------------- */
/** \name Private Keyboard Depressed Key Tracking
*
@ -7378,185 +7695,6 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title,
return window;
}
/**
* Show the buffer defined by #cursor_buffer_set without changing anything else,
* so #cursor_buffer_hide can be used to display it again.
*
* The caller is responsible for setting `seat->cursor.visible`.
*/
static void cursor_buffer_show(GWL_Seat *seat)
{
const GWL_Cursor *cursor = &seat->cursor;
if (seat->wl.pointer) {
const int scale = cursor->is_custom ? cursor->custom_scale : seat->pointer.theme_scale;
const int32_t hotspot_x = int32_t(cursor->wl.image.hotspot_x) / scale;
const int32_t hotspot_y = int32_t(cursor->wl.image.hotspot_y) / scale;
wl_pointer_set_cursor(
seat->wl.pointer, seat->pointer.serial, cursor->wl.surface_cursor, hotspot_x, hotspot_y);
}
if (!seat->wp.tablet_tools.empty()) {
const int scale = cursor->is_custom ? cursor->custom_scale : seat->tablet.theme_scale;
const int32_t hotspot_x = int32_t(cursor->wl.image.hotspot_x) / scale;
const int32_t hotspot_y = int32_t(cursor->wl.image.hotspot_y) / scale;
for (zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->wp.tablet_tools) {
GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(
zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2));
zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2,
seat->tablet.serial,
tablet_tool->wl.surface_cursor,
hotspot_x,
hotspot_y);
#ifdef USE_KDE_TABLET_HIDDEN_CURSOR_HACK
wl_surface_commit(tablet_tool->wl.surface_cursor);
#endif
}
}
cursor_anim_reset(seat);
}
/**
* Hide the buffer defined by #cursor_buffer_set without changing anything else,
* so #cursor_buffer_show can be used to display it again.
*
* The caller is responsible for setting `seat->cursor.visible`.
*/
static void cursor_buffer_hide(GWL_Seat *seat)
{
cursor_anim_end(seat);
wl_pointer_set_cursor(seat->wl.pointer, seat->pointer.serial, nullptr, 0, 0);
for (zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->wp.tablet_tools) {
zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2, seat->tablet.serial, nullptr, 0, 0);
}
}
/**
* Needed to ensure the cursor size is always a multiple of scale.
*/
static int cursor_buffer_compatible_scale_from_image(const wl_cursor_image *wl_image, int scale)
{
const int32_t image_size_x = int32_t(wl_image->width);
const int32_t image_size_y = int32_t(wl_image->height);
while (scale > 1) {
if ((image_size_x % scale) == 0 && (image_size_y % scale) == 0) {
break;
}
scale -= 1;
}
return scale;
}
static void cursor_buffer_set_surface_impl(const wl_cursor_image *wl_image,
wl_buffer *buffer,
wl_surface *wl_surface,
const int scale)
{
const int32_t image_size_x = int32_t(wl_image->width);
const int32_t image_size_y = int32_t(wl_image->height);
GHOST_ASSERT((image_size_x % scale) == 0 && (image_size_y % scale) == 0,
"The size must be a multiple of the scale!");
wl_surface_set_buffer_scale(wl_surface, scale);
wl_surface_attach(wl_surface, buffer, 0, 0);
wl_surface_damage(wl_surface, 0, 0, image_size_x, image_size_y);
wl_surface_commit(wl_surface);
}
static void cursor_buffer_set(const GWL_Seat *seat,
const wl_cursor_image *wl_image,
wl_buffer *buffer)
{
const GWL_Cursor *cursor = &seat->cursor;
const bool visible = (cursor->visible && cursor->is_hardware);
/* This is a requirement of WAYLAND, when this isn't the case,
* it causes Blender's window to close intermittently. */
if (seat->wl.pointer) {
const int scale = cursor_buffer_compatible_scale_from_image(
wl_image, cursor->is_custom ? cursor->custom_scale : seat->pointer.theme_scale);
const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale;
const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale;
cursor_buffer_set_surface_impl(wl_image, buffer, cursor->wl.surface_cursor, scale);
wl_pointer_set_cursor(seat->wl.pointer,
seat->pointer.serial,
visible ? cursor->wl.surface_cursor : nullptr,
hotspot_x,
hotspot_y);
}
/* Set the cursor for all tablet tools as well. */
if (!seat->wp.tablet_tools.empty()) {
const int scale = cursor_buffer_compatible_scale_from_image(
wl_image, cursor->is_custom ? cursor->custom_scale : seat->tablet.theme_scale);
const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale;
const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale;
for (zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->wp.tablet_tools) {
GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(
zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2));
cursor_buffer_set_surface_impl(wl_image, buffer, tablet_tool->wl.surface_cursor, scale);
zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2,
seat->tablet.serial,
visible ? tablet_tool->wl.surface_cursor : nullptr,
hotspot_x,
hotspot_y);
}
}
}
static void cursor_buffer_set_from_seat(GWL_Seat *seat)
{
const GWL_Cursor *cursor = &seat->cursor;
cursor_anim_end(seat);
cursor_buffer_set(seat, &cursor->wl.image, cursor->wl.buffer);
cursor_anim_begin_if_needed(seat);
}
enum eCursorSetMode {
CURSOR_VISIBLE_ALWAYS_SET = 1,
CURSOR_VISIBLE_ONLY_HIDE,
CURSOR_VISIBLE_ONLY_SHOW,
};
static void cursor_visible_set(GWL_Seat *seat,
const bool visible,
const bool is_hardware,
const enum eCursorSetMode set_mode)
{
GWL_Cursor *cursor = &seat->cursor;
const bool was_visible = cursor->is_hardware && cursor->visible;
const bool use_visible = is_hardware && visible;
if (set_mode == CURSOR_VISIBLE_ALWAYS_SET) {
/* Pass. */
}
else if (set_mode == CURSOR_VISIBLE_ONLY_SHOW) {
if (!use_visible) {
return;
}
}
else if (set_mode == CURSOR_VISIBLE_ONLY_HIDE) {
if (use_visible) {
return;
}
}
if (use_visible) {
if (!was_visible) {
cursor_buffer_show(seat);
}
}
else {
if (was_visible) {
cursor_buffer_hide(seat);
}
}
cursor->visible = visible;
cursor->is_hardware = is_hardware;
}
static bool cursor_is_software(const GHOST_TGrabCursorMode mode, const bool use_software_confine)
{
if (mode == GHOST_kGrabWrap) {
@ -7574,114 +7712,6 @@ static bool cursor_is_software(const GHOST_TGrabCursorMode mode, const bool use_
return false;
}
static bool cursor_anim_check(GWL_Seat *seat)
{
const wl_cursor *wl_cursor = seat->cursor.wl.theme_cursor;
if (!wl_cursor) {
return false;
}
/* NOTE: return true to stress test animated cursor,
* to ensure (otherwise rare) issues are triggered more frequently. */
// return true;
return wl_cursor->image_count > 1;
}
static void cursor_anim_begin(GWL_Seat *seat)
{
/* Caller must lock `server_mutex`. */
GHOST_ASSERT(seat->cursor.anim_handle == nullptr, "Must be cleared");
/* Callback for updating the cursor animation. */
auto cursor_anim_frame_step_fn =
[](GWL_Seat *seat, GWL_Cursor_AnimHandle *anim_handle, int delay) {
/* It's possible the `wl_cursor` is reloaded while the cursor is animating.
* Don't access outside the lock, that's why the `delay` is passed in. */
std::mutex *server_mutex = seat->system->server_mutex;
int frame = 0;
while (!anim_handle->exit_pending.load()) {
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
if (!anim_handle->exit_pending.load()) {
std::lock_guard lock_server_guard{*server_mutex};
if (!anim_handle->exit_pending.load()) {
const struct wl_cursor *wl_cursor = seat->cursor.wl.theme_cursor;
frame = (frame + 1) % wl_cursor->image_count;
wl_cursor_image *image = wl_cursor->images[frame];
wl_buffer *buffer = wl_cursor_image_get_buffer(image);
cursor_buffer_set(seat, image, buffer);
delay = wl_cursor->images[frame]->delay;
/* Without this the cursor won't update when other processes are occupied. */
wl_display_flush(seat->system->wl_display_get());
}
}
}
delete anim_handle;
};
/* Allocate so this can be set before the thread begins. */
GWL_Cursor_AnimHandle *anim_handle = new GWL_Cursor_AnimHandle;
seat->cursor.anim_handle = anim_handle;
const int delay = seat->cursor.wl.theme_cursor->images[0]->delay;
std::thread cursor_anim_thread(cursor_anim_frame_step_fn, seat, anim_handle, delay);
/* Application logic should take priority. */
thread_set_min_priority(cursor_anim_thread);
cursor_anim_thread.detach();
}
static void cursor_anim_begin_if_needed(GWL_Seat *seat)
{
if (cursor_anim_check(seat)) {
cursor_anim_begin(seat);
}
}
static void cursor_anim_end(GWL_Seat *seat)
{
GWL_Cursor *cursor = &seat->cursor;
if (cursor->anim_handle) {
GWL_Cursor_AnimHandle *anim_handle = cursor->anim_handle;
cursor->anim_handle = nullptr;
anim_handle->exit_pending.store(true);
}
}
static void cursor_anim_reset(GWL_Seat *seat)
{
cursor_anim_end(seat);
cursor_anim_begin_if_needed(seat);
}
static const wl_cursor *cursor_find_from_shape(GWL_Seat *seat,
const GHOST_TStandardCursor shape,
const char **r_cursor_name)
{
/* Caller must lock `server_mutex`. */
GWL_Cursor *cursor = &seat->cursor;
wl_cursor *wl_cursor = nullptr;
const char *cursor_name = ghost_wl_cursors.names[shape];
if (cursor_name[0] != '\0') {
if (!cursor->wl.theme) {
/* The cursor wl_surface hasn't entered an output yet. Initialize theme with scale 1. */
cursor->wl.theme = wl_cursor_theme_load(
cursor->theme_name.c_str(), cursor->theme_size, seat->system->wl_shm_get());
}
if (cursor->wl.theme) {
wl_cursor = wl_cursor_theme_get_cursor(cursor->wl.theme, cursor_name);
if (!wl_cursor) {
GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl);
}
}
}
if (r_cursor_name && wl_cursor) {
*r_cursor_name = cursor_name;
}
return wl_cursor;
}
GHOST_TSuccess GHOST_SystemWayland::cursor_shape_set(const GHOST_TStandardCursor shape)
{
/* Caller must lock `server_mutex`. */
@ -7692,7 +7722,7 @@ GHOST_TSuccess GHOST_SystemWayland::cursor_shape_set(const GHOST_TStandardCursor
}
const char *cursor_name = nullptr;
const wl_cursor *wl_cursor = cursor_find_from_shape(seat, shape, &cursor_name);
const wl_cursor *wl_cursor = gwl_seat_cursor_find_from_shape(seat, shape, &cursor_name);
if (wl_cursor == nullptr) {
return GHOST_kFailure;
}
@ -7711,7 +7741,7 @@ GHOST_TSuccess GHOST_SystemWayland::cursor_shape_set(const GHOST_TStandardCursor
cursor->wl.theme_cursor = wl_cursor;
cursor->wl.theme_cursor_name = cursor_name;
cursor_buffer_set_from_seat(seat);
gwl_seat_cursor_buffer_set_current(seat);
return GHOST_kSuccess;
}
@ -7720,7 +7750,7 @@ GHOST_TSuccess GHOST_SystemWayland::cursor_shape_check(const GHOST_TStandardCurs
{
/* No need to lock `server_mutex`. */
GWL_Seat *seat = gwl_display_seat_active_get(display_);
const wl_cursor *wl_cursor = cursor_find_from_shape(seat, cursorShape, nullptr);
const wl_cursor *wl_cursor = gwl_seat_cursor_find_from_shape(seat, cursorShape, nullptr);
if (wl_cursor == nullptr) {
return GHOST_kFailure;
}
@ -7800,7 +7830,7 @@ GHOST_TSuccess GHOST_SystemWayland::cursor_shape_custom_set(const uint8_t *bitma
cursor->wl.theme_cursor = nullptr;
cursor->wl.theme_cursor_name = nullptr;
cursor_buffer_set_from_seat(seat);
gwl_seat_cursor_buffer_set_current(seat);
return GHOST_kSuccess;
}
@ -7840,7 +7870,7 @@ GHOST_TSuccess GHOST_SystemWayland::cursor_visibility_set(const bool visible)
return GHOST_kFailure;
}
cursor_visible_set(seat, visible, seat->cursor.is_hardware, CURSOR_VISIBLE_ALWAYS_SET);
gwl_seat_cursor_visible_set(seat, visible, seat->cursor.is_hardware, CURSOR_VISIBLE_ALWAYS_SET);
return GHOST_kSuccess;
}
@ -8432,7 +8462,7 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
/* Only hide so the cursor is not made visible before it's location is restored.
* This function is called again at the end of this function which only shows. */
cursor_visible_set(seat, use_visible, is_hardware_cursor, CURSOR_VISIBLE_ONLY_HIDE);
gwl_seat_cursor_visible_set(seat, use_visible, is_hardware_cursor, CURSOR_VISIBLE_ONLY_HIDE);
/* Switching from one grab mode to another,
* in this case disable the current locks as it makes logic confusing,
@ -8574,7 +8604,7 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
}
/* Only show so the cursor is made visible as the last step. */
cursor_visible_set(seat, use_visible, is_hardware_cursor, CURSOR_VISIBLE_ONLY_SHOW);
gwl_seat_cursor_visible_set(seat, use_visible, is_hardware_cursor, CURSOR_VISIBLE_ONLY_SHOW);
#ifdef USE_GNOME_CONFINE_HACK
seat->use_pointer_software_confine = use_software_confine;

@ -885,7 +885,7 @@ static void gwl_window_frame_update_from_pending_no_lock(GWL_Window *win)
win->frame_pending.size[1] = 0;
}
static void gwl_window_frame_update_from_pending(GWL_Window *win)
[[maybe_unused]] static void gwl_window_frame_update_from_pending(GWL_Window *win)
{
#ifdef USE_EVENT_BACKGROUND_THREAD
std::lock_guard lock_frame_guard{win->frame_pending_mutex};