From 2d7ec208c42b6a354da33e8f4256d43cebbcdc1d Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Thu, 12 Jan 2023 01:29:25 +0000 Subject: [PATCH] sdlwindow: Forward cursor in absolute mode to host compositor --- src/sdlwindow.cpp | 59 ++++++++++++++++++++++++++++++++++++++++++++ src/sdlwindow.hpp | 1 + src/steamcompmgr.cpp | 20 +++++++++------ src/steamcompmgr.hpp | 2 ++ 4 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/sdlwindow.cpp b/src/sdlwindow.cpp index a4e5083..b7df72d 100644 --- a/src/sdlwindow.cpp +++ b/src/sdlwindow.cpp @@ -34,6 +34,7 @@ enum UserEvents USER_EVENT_TITLE, USER_EVENT_VISIBLE, USER_EVENT_GRAB, + USER_EVENT_CURSOR, USER_EVENT_COUNT }; @@ -44,6 +45,15 @@ static std::mutex g_SDLWindowTitleLock; static std::string g_SDLWindowTitle; static bool g_bUpdateSDLWindowTitle = false; +struct SDLPendingCursor +{ + uint32_t width, height, xhot, yhot; + std::vector data; +}; +static std::mutex g_SDLCursorLock; +static SDLPendingCursor g_SDLPendingCursorData; +static bool g_bUpdateSDLCursor = false; + //----------------------------------------------------------------------------- // Purpose: Convert from the remote scancode to a Linux event keycode //----------------------------------------------------------------------------- @@ -316,6 +326,24 @@ void inputSDLThreadRun( void ) bRelativeMouse = grab; } } + if ( event.type == g_unSDLUserEventID + USER_EVENT_CURSOR ) + { + std::unique_lock lock(g_SDLCursorLock); + if ( g_bUpdateSDLCursor ) + { + SDL_Surface *surface = SDL_CreateRGBSurfaceFrom( + g_SDLPendingCursorData.data.data(), + g_SDLPendingCursorData.width, + g_SDLPendingCursorData.height, + 32, + g_SDLPendingCursorData.width * sizeof(uint32_t), + 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); + + SDL_Cursor *cursor = SDL_CreateColorCursor( surface, g_SDLPendingCursorData.xhot, g_SDLPendingCursorData.yhot ); + SDL_SetCursor( cursor ); + g_bUpdateSDLCursor = false; + } + } break; } } @@ -372,8 +400,39 @@ void sdlwindow_grab( bool bGrab ) if ( g_bForceRelativeMouse ) return; + static bool s_bWasGrabbed = false; + + if ( s_bWasGrabbed == bGrab ) + return; + + s_bWasGrabbed = bGrab; + SDL_Event event; event.type = g_unSDLUserEventID + USER_EVENT_GRAB; event.user.code = bGrab ? 1 : 0; SDL_PushEvent( &event ); } + +void sdlwindow_cursor(void* pixels, uint32_t width, uint32_t height, uint32_t xhot, uint32_t yhot) +{ + if ( !BIsNested() ) + return; + + if ( g_bForceRelativeMouse ) + return; + + { + std::unique_lock lock( g_SDLCursorLock ); + g_SDLPendingCursorData.width = width; + g_SDLPendingCursorData.height = height; + g_SDLPendingCursorData.xhot = xhot; + g_SDLPendingCursorData.yhot = yhot; + g_SDLPendingCursorData.data.resize( width * height ); + memcpy(g_SDLPendingCursorData.data.data(), pixels, width * height * sizeof(uint32_t)); + g_bUpdateSDLCursor = true; + } + + SDL_Event event; + event.type = g_unSDLUserEventID + USER_EVENT_CURSOR; + SDL_PushEvent( &event ); +} diff --git a/src/sdlwindow.hpp b/src/sdlwindow.hpp index 5bfce11..5ddf878 100644 --- a/src/sdlwindow.hpp +++ b/src/sdlwindow.hpp @@ -13,5 +13,6 @@ void sdlwindow_title( const char* title ); // called from other threads with interesting things have happened with clients that might warrant updating the nested window void sdlwindow_visible( bool bVisible ); void sdlwindow_grab( bool bGrab ); +void sdlwindow_cursor(void* pixels, uint32_t width, uint32_t height, uint32_t xhot, uint32_t yhot); extern SDL_Window *g_SDLWindow; diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp index 2b7f15f..7d8bf0d 100644 --- a/src/steamcompmgr.cpp +++ b/src/steamcompmgr.cpp @@ -1364,14 +1364,12 @@ bool MouseCursor::getTexture() } } - if (bNoCursor != m_imageEmpty) { - m_imageEmpty = bNoCursor; + m_imageEmpty = bNoCursor; - if ( !g_bForceRelativeMouse ) - { - sdlwindow_grab( m_imageEmpty ); - bSteamCompMgrGrab = BIsNested() && m_imageEmpty; - } + if ( !g_bForceRelativeMouse ) + { + sdlwindow_grab( m_imageEmpty ); + bSteamCompMgrGrab = BIsNested() && m_imageEmpty; } m_dirty = false; @@ -1391,6 +1389,7 @@ bool MouseCursor::getTexture() } m_texture = vulkan_create_texture_from_bits(surfaceWidth, surfaceHeight, image->width, image->height, DRM_FORMAT_ARGB8888, texCreateFlags, cursorBuffer.data()); + sdlwindow_cursor(cursorBuffer.data(), image->width, image->height, image->xhot, image->yhot); assert(m_texture); XFree(image); @@ -1910,6 +1909,13 @@ paint_all(bool async) } } + if (input) + { + // Make sure to un-dirty the texture before we do any painting logic. + // We determine whether we are grabbed etc this way. + global_focus.cursor->undirty(); + } + bool bForceHideCursor = BIsNested() && !bSteamCompMgrGrab; bool bDrewCursor = false; diff --git a/src/steamcompmgr.hpp b/src/steamcompmgr.hpp index e824c60..4d15164 100644 --- a/src/steamcompmgr.hpp +++ b/src/steamcompmgr.hpp @@ -71,6 +71,8 @@ public: m_y = y; } + void undirty() { getTexture(); } + private: void warp(int x, int y); void checkSuspension();