initial hyprcursor support

This commit is contained in:
Vaxry 2024-03-07 17:51:47 +00:00
parent 6c4e2489a0
commit 8e8c4352e5
10 changed files with 209 additions and 34 deletions

View File

@ -101,7 +101,7 @@ message(STATUS "Checking deps...")
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
find_package(OpenGL REQUIRED)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1 hyprlang>=0.3.2) # we do not check for wlroots, as we provide it ourselves
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo libdrm xkbcommon libinput pango pangocairo pixman-1 hyprlang>=0.3.2 hyprcursor) # we do not check for wlroots, as we provide it ourselves
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")

View File

@ -1,6 +1,7 @@
#include "Compositor.hpp"
#include "helpers/Splashes.hpp"
#include "config/ConfigValue.hpp"
#include "managers/CursorManager.hpp"
#include <random>
#include <unordered_set>
#include "debug/HyprCtl.hpp"
@ -182,18 +183,6 @@ void CCompositor::initServer() {
m_sWLRCursor = wlr_cursor_create();
wlr_cursor_attach_output_layout(m_sWLRCursor, m_sWLROutputLayout);
if (const auto XCURSORENV = getenv("XCURSOR_SIZE"); !XCURSORENV || std::string(XCURSORENV).empty())
setenv("XCURSOR_SIZE", "24", true);
const auto XCURSORENV = getenv("XCURSOR_SIZE");
int cursorSize = 24;
try {
cursorSize = std::stoi(XCURSORENV);
} catch (std::exception& e) { Debug::log(ERR, "XCURSOR_SIZE invalid in check #2? ({})", XCURSORENV); }
m_sWLRXCursorMgr = wlr_xcursor_manager_create(nullptr, cursorSize);
wlr_xcursor_manager_load(m_sWLRXCursorMgr, 1);
m_sSeat.seat = wlr_seat_create(m_sWLDisplay, "seat0");
m_sWLRPresentation = wlr_presentation_create(m_sWLDisplay, m_sWLRBackend);
@ -422,6 +411,7 @@ void CCompositor::cleanup() {
wl_display_destroy_clients(g_pCompositor->m_sWLDisplay);
g_pDecorationPositioner.reset();
g_pCursorManager.reset();
g_pPluginSystem.reset();
g_pHyprNotificationOverlay.reset();
g_pDebugOverlay.reset();
@ -511,6 +501,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Debug::log(LOG, "Creating the DecorationPositioner!");
g_pDecorationPositioner = std::make_unique<CDecorationPositioner>();
Debug::log(LOG, "Creating the CursorManager!");
g_pCursorManager = std::make_unique<CCursorManager>();
} break;
default: UNREACHABLE();
}

View File

@ -57,7 +57,6 @@ class CCompositor {
wlr_layer_shell_v1* m_sWLRLayerShell;
wlr_xdg_shell* m_sWLRXDGShell;
wlr_cursor* m_sWLRCursor;
wlr_xcursor_manager* m_sWLRXCursorMgr;
wlr_virtual_keyboard_manager_v1* m_sWLRVKeyboardMgr;
wlr_output_manager_v1* m_sWLROutputMgr;
wlr_presentation* m_sWLRPresentation;

View File

@ -16,6 +16,7 @@
#include <typeindex>
#include "../config/ConfigValue.hpp"
#include "../managers/CursorManager.hpp"
static void trimTrailingComma(std::string& str) {
if (!str.empty() && str.back() == ',')
@ -1039,16 +1040,7 @@ std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request)
if (size <= 0)
return "size not positive";
wlr_xcursor_manager_destroy(g_pCompositor->m_sWLRXCursorMgr);
g_pCompositor->m_sWLRXCursorMgr = wlr_xcursor_manager_create(theme.c_str(), size);
setenv("XCURSOR_SIZE", SIZESTR.c_str(), true);
setenv("XCURSOR_THEME", theme.c_str(), true);
for (auto& m : g_pCompositor->m_vMonitors) {
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, m->scale);
}
g_pCursorManager->changeTheme(theme, size);
return "ok";
}

View File

@ -4,6 +4,7 @@
#include "../helpers/WLClasses.hpp"
#include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp"
#include "../managers/CursorManager.hpp"
// ------------------------------ //
// __ __ _____ _____ _____ //
@ -67,10 +68,10 @@ void Events::listener_readyXWayland(wl_listener* listener, void* data) {
wlr_xwayland_set_seat(g_pXWaylandManager->m_sWLRXWayland, g_pCompositor->m_sSeat.seat);
const auto XCURSOR = wlr_xcursor_manager_get_xcursor(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", 1);
if (XCURSOR) {
wlr_xwayland_set_cursor(g_pXWaylandManager->m_sWLRXWayland, XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, XCURSOR->images[0]->width,
XCURSOR->images[0]->height, XCURSOR->images[0]->hotspot_x, XCURSOR->images[0]->hotspot_y);
const auto CURSOR = g_pCursorManager->dataFor("left_ptr");
if (CURSOR.surface) {
wlr_xwayland_set_cursor(g_pXWaylandManager->m_sWLRXWayland, cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), CURSOR.size,
CURSOR.size, CURSOR.hotspotX, CURSOR.hotspotY);
}
xcb_disconnect(XCBCONNECTION);

View File

@ -164,8 +164,6 @@ void CMonitor::onConnect(bool noRule) {
wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y);
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
Debug::log(LOG, "Added new monitor with name {} at {:j0} with size {:j0}, pointer {:x}", output->name, vecPosition, vecPixelSize, (uintptr_t)output);
setupDefaultWS(monitorRule);
@ -192,8 +190,6 @@ void CMonitor::onConnect(bool noRule) {
if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet
g_pCompositor->setActiveMonitor(this);
wlr_xcursor_manager_load(g_pCompositor->m_sWLRXCursorMgr, scale);
g_pHyprRenderer->arrangeLayersForMonitor(ID);
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID);

View File

@ -63,7 +63,6 @@ extern "C" {
#include <wlr/types/wlr_server_decoration.h>
#include <wlr/types/wlr_viewporter.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/types/wlr_xdg_activation_v1.h>
#include <wlr/types/wlr_xdg_decoration_v1.h>
#include <wlr/types/wlr_xdg_output_v1.h>
@ -76,6 +75,7 @@ extern "C" {
#include <wlr/types/wlr_idle_inhibit_v1.h>
#include <wlr/util/log.h>
#include <wlr/util/region.h>
#include <wlr/util/edges.h>
#include <wlr/types/wlr_tablet_pad.h>
#include <wlr/types/wlr_tablet_tool.h>
#include <wlr/types/wlr_tablet_v2.h>

View File

@ -0,0 +1,137 @@
#include "CursorManager.hpp"
#include "Compositor.hpp"
extern "C" {
#include <wlr/interfaces/wlr_buffer.h>
}
CCursorManager::CCursorManager() {
m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(m_szTheme.empty() ? nullptr : m_szTheme.c_str());
// find default size. First, HYPRCURSOR_SIZE, then XCURSOR_SIZE, then 24
auto SIZE = getenv("HYPRCURSOR_SIZE");
if (SIZE) {
try {
m_iSize = std::stoi(SIZE);
} catch (...) { ; }
}
SIZE = getenv("XCURSOR_SIZE");
if (SIZE && m_iSize == 0) {
try {
m_iSize = std::stoi(SIZE);
} catch (...) { ; }
}
if (m_iSize == 0)
m_iSize = 24;
updateTheme();
g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, std::any param) { this->updateTheme(); });
}
static void cursorBufferDestroy(struct wlr_buffer* wlr_buffer) {
CCursorManager::CCursorBuffer::SCursorWlrBuffer* buffer = wl_container_of(wlr_buffer, buffer, base);
buffer->dropped = true;
}
static bool cursorBufferBeginDataPtr(struct wlr_buffer* wlr_buffer, uint32_t flags, void** data, uint32_t* format, size_t* stride) {
CCursorManager::CCursorBuffer::SCursorWlrBuffer* buffer = wl_container_of(wlr_buffer, buffer, base);
if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE)
return false;
*data = cairo_image_surface_get_data(buffer->surface);
*stride = cairo_image_surface_get_stride(buffer->surface);
*format = DRM_FORMAT_ARGB8888;
return true;
}
static void cursorBufferEndDataPtr(struct wlr_buffer* wlr_buffer) {
;
}
//
static const wlr_buffer_impl bufferImpl = {
.destroy = cursorBufferDestroy,
.begin_data_ptr_access = cursorBufferBeginDataPtr,
.end_data_ptr_access = cursorBufferEndDataPtr,
};
CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : size(size_), hotspot(hot_) {
wlrBuffer.surface = surf;
wlr_buffer_init(&wlrBuffer.base, &bufferImpl, size.x, size.y);
}
CCursorManager::CCursorBuffer::~CCursorBuffer() {
if (g_pCursorManager->m_bOurBufferConnected)
wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, nullptr, 0, 0);
if (!wlrBuffer.dropped)
wlr_buffer_drop(&wlrBuffer.base);
}
wlr_buffer* CCursorManager::getCursorBuffer() {
return m_sCursorBuffer ? &m_sCursorBuffer->wlrBuffer.base : nullptr;
}
void CCursorManager::setCursorSurface(wlr_surface* surf, const Vector2D& hotspot) {
wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, surf, hotspot.x, hotspot.y);
m_bOurBufferConnected = false;
}
void CCursorManager::setCursorFromName(const std::string& name) {
if (m_sCursorBuffer)
m_sCursorBuffer.reset();
const auto IMAGES = m_pHyprcursor->getShape(name.c_str(), m_sCurrentStyleInfo);
m_sCursorBuffer = std::make_unique<CCursorBuffer>(IMAGES.images[0].surface, Vector2D{IMAGES.images[0].size, IMAGES.images[0].size},
Vector2D{IMAGES.images[0].hotspotX, IMAGES.images[0].hotspotY});
if (g_pCompositor->m_sWLRCursor)
wlr_cursor_set_buffer(g_pCompositor->m_sWLRCursor, getCursorBuffer(), IMAGES.images[0].hotspotX, IMAGES.images[0].hotspotY, m_fCursorScale);
m_bOurBufferConnected = true;
}
SCursorImageData CCursorManager::dataFor(const std::string& name) {
const auto IMAGES = m_pHyprcursor->getShape(name.c_str(), m_sCurrentStyleInfo);
if (IMAGES.images.empty())
return {};
return IMAGES.images[0];
}
void CCursorManager::updateTheme() {
float highestScale = 1.0;
for (auto& m : g_pCompositor->m_vMonitors) {
if (m->scale > highestScale)
highestScale = m->scale;
}
if (highestScale * m_iSize == m_sCurrentStyleInfo.size)
return;
if (m_sCurrentStyleInfo.size)
m_pHyprcursor->cursorSurfaceStyleDone(m_sCurrentStyleInfo);
m_sCurrentStyleInfo.size = m_iSize * highestScale;
m_fCursorScale = highestScale;
m_pHyprcursor->loadThemeStyle(m_sCurrentStyleInfo);
setCursorFromName("left_ptr");
}
void CCursorManager::changeTheme(const std::string& name, const int size) {
m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(name.empty() ? "" : name.c_str(), size);
m_szTheme = name;
m_iSize = size;
updateTheme();
}

View File

@ -0,0 +1,56 @@
#pragma once
#include <string>
#include <hyprcursor/hyprcursor.hpp>
#include <memory>
#include "../includes.hpp"
#include "../helpers/Vector2D.hpp"
struct wlr_buffer;
class CCursorManager {
public:
CCursorManager();
wlr_buffer* getCursorBuffer();
void setCursorFromName(const std::string& name);
void setCursorSurface(wlr_surface* surf, const Vector2D& hotspot);
void changeTheme(const std::string& name, const int size);
void updateTheme();
SCursorImageData dataFor(const std::string& name); // for xwayland
class CCursorBuffer {
public:
CCursorBuffer(cairo_surface_t* surf, const Vector2D& size, const Vector2D& hotspot);
~CCursorBuffer();
struct SCursorWlrBuffer {
wlr_buffer base;
cairo_surface_t* surface = nullptr;
bool dropped = false;
} wlrBuffer;
private:
Vector2D size;
Vector2D hotspot;
friend class CCursorManager;
};
bool m_bOurBufferConnected = false;
private:
std::unique_ptr<CCursorBuffer> m_sCursorBuffer;
std::unique_ptr<Hyprcursor::CHyprcursorManager> m_pHyprcursor;
std::string m_szTheme = "";
int m_iSize = 24;
float m_fCursorScale = 1.0;
Hyprcursor::SCursorStyleInfo m_sCurrentStyleInfo;
};
inline std::unique_ptr<CCursorManager> g_pCursorManager;

View File

@ -4,6 +4,7 @@
#include "../helpers/Region.hpp"
#include <algorithm>
#include "../config/ConfigValue.hpp"
#include "../managers/CursorManager.hpp"
extern "C" {
#include <xf86drm.h>
@ -2193,7 +2194,7 @@ void CHyprRenderer::setCursorFromName(const std::string& name, bool force) {
if (m_bCursorHidden && !force)
return;
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sWLRXCursorMgr, name.c_str());
g_pCursorManager->setCursorFromName(name);
}
void CHyprRenderer::ensureCursorRenderingMode() {