diff --git a/intern/ghost/intern/GHOST_SystemWayland.cc b/intern/ghost/intern/GHOST_SystemWayland.cc index f3ce36bc714..d7743736fe7 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cc +++ b/intern/ghost/intern/GHOST_SystemWayland.cc @@ -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(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( + 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( + 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( - 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( - 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; diff --git a/intern/ghost/intern/GHOST_WindowWayland.cc b/intern/ghost/intern/GHOST_WindowWayland.cc index db92aedb6a0..c938e7969e9 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.cc +++ b/intern/ghost/intern/GHOST_WindowWayland.cc @@ -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};