diff --git a/src/defer.hpp b/src/defer.hpp new file mode 100644 index 0000000..1fcbe53 --- /dev/null +++ b/src/defer.hpp @@ -0,0 +1,32 @@ +#pragma once + +namespace defer_detail +{ + template + class DeferHelper + { + public: + DeferHelper(Func func) + : m_func(func) + { + } + ~DeferHelper() + { + m_func(); + } + + private: + Func m_func; + }; + + template + DeferHelper CreateDeferHelper(Func func) + { + return DeferHelper(func); + } +} + +#define DEFER_1(x, y) x##y +#define DEFER_2(x, y) DEFER_1(x, y) +#define DEFER_3(x) DEFER_2(x, __COUNTER__) +#define defer(code) auto DEFER_3(_defer_) = defer_detail::CreateDeferHelper( [&](){ code; } ) diff --git a/src/meson.build b/src/meson.build index e141edd..1adf8f1 100644 --- a/src/meson.build +++ b/src/meson.build @@ -6,6 +6,7 @@ dep_xfixes = dependency('xfixes') dep_xxf86vm = dependency('xxf86vm') dep_xtst = dependency('xtst') dep_xres = dependency('xres') +dep_xmu = dependency('xmu') drm_dep = dependency('libdrm', version: '>= 2.4.113') @@ -113,7 +114,7 @@ endif dep_x11, dep_xdamage, dep_xcomposite, dep_xrender, dep_xext, dep_xfixes, dep_xxf86vm, dep_xres, drm_dep, wayland_server, xkbcommon, thread_dep, sdl_dep, wlroots_dep, - vulkan_dep, liftoff_dep, dep_xtst, cap_dep, pipewire_dep, librt_dep, + vulkan_dep, liftoff_dep, dep_xtst, dep_xmu, cap_dep, pipewire_dep, librt_dep, stb_dep, displayinfo_dep, openvr_dep, ], install: true, diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp index beedc85..ac943ed 100644 --- a/src/steamcompmgr.cpp +++ b/src/steamcompmgr.cpp @@ -66,6 +66,7 @@ #include #include #include +#include #include "xwayland_ctx.hpp" @@ -77,6 +78,7 @@ #include "vblankmanager.hpp" #include "sdlwindow.hpp" #include "log.hpp" +#include "defer.hpp" #if HAVE_PIPEWIRE #include "pipewire.hpp" @@ -1167,6 +1169,38 @@ error_image: return false; } +bool MouseCursor::setCursorImageByName(const char *name) +{ + int screen = DefaultScreen(m_ctx->dpy); + + XColor fg; + fg.pixel = WhitePixel(m_ctx->dpy, screen); + XQueryColor(m_ctx->dpy, DefaultColormap(m_ctx->dpy, screen), &fg); + + XColor bg; + bg.pixel = BlackPixel(m_ctx->dpy, screen); + XQueryColor(m_ctx->dpy, DefaultColormap(m_ctx->dpy, screen), &bg); + + int index = XmuCursorNameToIndex(name); + if (index < 0) + return false; + + Font font = XLoadFont(m_ctx->dpy, "cursor"); + if (!font) + return false; + defer( XUnloadFont(m_ctx->dpy, font) ); + + Cursor cursor = XCreateGlyphCursor(m_ctx->dpy, font, font, index, index + 1, &fg, &bg); + if ( !cursor ) + return false; + defer( XFreeCursor(m_ctx->dpy, cursor) ); + + XDefineCursor(m_ctx->dpy, DefaultRootWindow(m_ctx->dpy), cursor); + XFlush(m_ctx->dpy); + setDirty(); + return true; +} + void MouseCursor::constrainPosition() { int i; @@ -5594,6 +5628,10 @@ void init_xwayland_ctx(gamescope_xwayland_server_t *xwayland_server) if (!load_mouse_cursor(ctx->cursor.get(), g_customCursorPath, g_customCursorHotspotX, g_customCursorHotspotY)) xwm_log.errorf("Failed to load mouse cursor: %s", g_customCursorPath); } + else + { + ctx->cursor->setCursorImageByName("left_ptr"); + } } void update_vrr_atoms(xwayland_ctx_t *root_ctx, bool force) diff --git a/src/steamcompmgr.hpp b/src/steamcompmgr.hpp index f7b9344..e824c60 100644 --- a/src/steamcompmgr.hpp +++ b/src/steamcompmgr.hpp @@ -58,6 +58,7 @@ public: // Will take ownership of data. bool setCursorImage(char *data, int w, int h, int hx, int hy); + bool setCursorImageByName(const char *name); void hide() { m_lastMovedTime = 0; checkSuspension(); }