mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-03 13:41:59 -07:00
Core: Move to aquamarine (#6608)
Moves Hyprland from wlroots to aquamarine for the backend. --------- Signed-off-by: Vaxry <vaxry@vaxry.net> Co-authored-by: Mihai Fufezan <mihai@fufexan.net> Co-authored-by: Jan Beich <jbeich@FreeBSD.org> Co-authored-by: vaxerski <vaxerski@users.noreply.github.com> Co-authored-by: UjinT34 <41110182+UjinT34@users.noreply.github.com> Co-authored-by: Tom Englund <tomenglund26@gmail.com> Co-authored-by: Ikalco <73481042+ikalco@users.noreply.github.com> Co-authored-by: diniamo <diniamo53@gmail.com>
This commit is contained in:
@@ -3,10 +3,11 @@
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "PointerManager.hpp"
|
||||
#include "../xwayland/XWayland.hpp"
|
||||
#include <cstring>
|
||||
#include "../helpers/CursorShapes.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include <wlr/interfaces/wlr_buffer.h>
|
||||
#include <wlr/types/wlr_xcursor_manager.h>
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
}
|
||||
|
||||
static int cursorAnimTimer(void* data) {
|
||||
@@ -45,8 +46,7 @@ CCursorManager::CCursorManager() {
|
||||
if (m_iSize == 0)
|
||||
m_iSize = 24;
|
||||
|
||||
m_pWLRXCursorMgr = wlr_xcursor_manager_create(getenv("XCURSOR_THEME"), m_iSize);
|
||||
wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0);
|
||||
xcursor.loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "", m_iSize * std::ceil(m_fCursorScale));
|
||||
|
||||
m_pAnimationTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ::cursorAnimTimer, nullptr);
|
||||
|
||||
@@ -56,9 +56,6 @@ CCursorManager::CCursorManager() {
|
||||
}
|
||||
|
||||
CCursorManager::~CCursorManager() {
|
||||
if (m_pWLRXCursorMgr)
|
||||
wlr_xcursor_manager_destroy(m_pWLRXCursorMgr);
|
||||
|
||||
if (m_pAnimationTimer)
|
||||
wl_event_source_remove(m_pAnimationTimer);
|
||||
}
|
||||
@@ -67,54 +64,61 @@ void CCursorManager::dropBufferRef(CCursorManager::CCursorBuffer* ref) {
|
||||
std::erase_if(m_vCursorBuffers, [ref](const auto& buf) { return buf.get() == ref; });
|
||||
}
|
||||
|
||||
static void cursorBufferDestroy(struct wlr_buffer* wlr_buffer) {
|
||||
CCursorManager::CCursorBuffer::SCursorWlrBuffer* buffer = wl_container_of(wlr_buffer, buffer, base);
|
||||
g_pCursorManager->dropBufferRef(buffer->parent);
|
||||
CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) {
|
||||
surface = surf;
|
||||
size = size_;
|
||||
stride = cairo_image_surface_get_stride(surf);
|
||||
}
|
||||
|
||||
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 = buffer->pixelData ? buffer->pixelData : cairo_image_surface_get_data(buffer->surface);
|
||||
*stride = buffer->stride;
|
||||
*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);
|
||||
wlrBuffer.parent = this;
|
||||
wlrBuffer.stride = cairo_image_surface_get_stride(surf);
|
||||
}
|
||||
|
||||
CCursorManager::CCursorBuffer::CCursorBuffer(uint8_t* pixelData, const Vector2D& size_, const Vector2D& hot_) : size(size_), hotspot(hot_) {
|
||||
wlrBuffer.pixelData = pixelData;
|
||||
wlr_buffer_init(&wlrBuffer.base, &bufferImpl, size.x, size.y);
|
||||
wlrBuffer.parent = this;
|
||||
wlrBuffer.stride = 4 * size_.x;
|
||||
CCursorManager::CCursorBuffer::CCursorBuffer(uint8_t* pixelData_, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) {
|
||||
pixelData = pixelData_;
|
||||
size = size_;
|
||||
stride = 4 * size_.x;
|
||||
}
|
||||
|
||||
CCursorManager::CCursorBuffer::~CCursorBuffer() {
|
||||
; // will be freed in .destroy
|
||||
;
|
||||
}
|
||||
|
||||
wlr_buffer* CCursorManager::getCursorBuffer() {
|
||||
return !m_vCursorBuffers.empty() ? &m_vCursorBuffers.back()->wlrBuffer.base : nullptr;
|
||||
Aquamarine::eBufferCapability CCursorManager::CCursorBuffer::caps() {
|
||||
return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR;
|
||||
}
|
||||
|
||||
Aquamarine::eBufferType CCursorManager::CCursorBuffer::type() {
|
||||
return Aquamarine::eBufferType::BUFFER_TYPE_SHM;
|
||||
}
|
||||
|
||||
void CCursorManager::CCursorBuffer::update(const Hyprutils::Math::CRegion& damage) {
|
||||
;
|
||||
}
|
||||
|
||||
bool CCursorManager::CCursorBuffer::isSynchronous() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCursorManager::CCursorBuffer::good() {
|
||||
return true;
|
||||
}
|
||||
|
||||
Aquamarine::SSHMAttrs CCursorManager::CCursorBuffer::shm() {
|
||||
Aquamarine::SSHMAttrs attrs;
|
||||
attrs.success = true;
|
||||
attrs.format = DRM_FORMAT_ARGB8888;
|
||||
attrs.size = size;
|
||||
attrs.stride = stride;
|
||||
return attrs;
|
||||
}
|
||||
|
||||
std::tuple<uint8_t*, uint32_t, size_t> CCursorManager::CCursorBuffer::beginDataPtr(uint32_t flags) {
|
||||
return {pixelData ? pixelData : cairo_image_surface_get_data(surface), DRM_FORMAT_ARGB8888, stride};
|
||||
}
|
||||
|
||||
void CCursorManager::CCursorBuffer::endDataPtr() {
|
||||
;
|
||||
}
|
||||
|
||||
SP<Aquamarine::IBuffer> CCursorManager::getCursorBuffer() {
|
||||
return !m_vCursorBuffers.empty() ? m_vCursorBuffers.back() : nullptr;
|
||||
}
|
||||
|
||||
void CCursorManager::setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot) {
|
||||
@@ -127,34 +131,24 @@ void CCursorManager::setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotsp
|
||||
}
|
||||
|
||||
void CCursorManager::setXCursor(const std::string& name) {
|
||||
if (!m_pWLRXCursorMgr) {
|
||||
g_pPointerManager->resetCursorImage();
|
||||
return;
|
||||
}
|
||||
|
||||
float scale = std::ceil(m_fCursorScale);
|
||||
wlr_xcursor_manager_load(m_pWLRXCursorMgr, scale);
|
||||
|
||||
auto xcursor = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, name.c_str(), scale);
|
||||
if (!xcursor) {
|
||||
Debug::log(ERR, "XCursor has no shape {}, retrying with left-ptr", name);
|
||||
xcursor = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, "left-ptr", scale);
|
||||
}
|
||||
|
||||
if (!xcursor || !xcursor->images[0]) {
|
||||
Debug::log(ERR, "XCursor is broken. F this garbage.");
|
||||
if (!xcursor.themeLoaded) {
|
||||
Debug::log(ERR, "XCursor failed to find theme in setXCursor");
|
||||
g_pPointerManager->resetCursorImage();
|
||||
return;
|
||||
}
|
||||
|
||||
auto image = xcursor->images[0];
|
||||
auto& icon = xcursor.defaultCursor;
|
||||
// try to get an icon we know if we have one
|
||||
if (xcursor.cursors.contains(name))
|
||||
icon = xcursor.cursors.at(name);
|
||||
|
||||
m_vCursorBuffers.emplace_back(
|
||||
std::make_unique<CCursorBuffer>(image->buffer, Vector2D{(int)image->width, (int)image->height}, Vector2D{(double)image->hotspot_x, (double)image->hotspot_y}));
|
||||
m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>((uint8_t*)icon->pixels.data(), icon->size, icon->hotspot));
|
||||
|
||||
g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{(double)image->hotspot_x, (double)image->hotspot_y} / scale, scale);
|
||||
g_pPointerManager->setCursorBuffer(getCursorBuffer(), icon->hotspot / scale, scale);
|
||||
if (m_vCursorBuffers.size() > 1)
|
||||
wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base);
|
||||
dropBufferRef(m_vCursorBuffers.at(0).get());
|
||||
|
||||
m_bOurBufferConnected = true;
|
||||
}
|
||||
@@ -196,14 +190,14 @@ void CCursorManager::setCursorFromName(const std::string& name) {
|
||||
}
|
||||
}
|
||||
|
||||
m_vCursorBuffers.emplace_back(std::make_unique<CCursorBuffer>(m_sCurrentCursorShapeData.images[0].surface,
|
||||
Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size},
|
||||
Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY}));
|
||||
m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>(m_sCurrentCursorShapeData.images[0].surface,
|
||||
Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size},
|
||||
Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY}));
|
||||
|
||||
g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY} / m_fCursorScale,
|
||||
m_fCursorScale);
|
||||
if (m_vCursorBuffers.size() > 1)
|
||||
wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base);
|
||||
dropBufferRef(m_vCursorBuffers.at(0).get());
|
||||
|
||||
m_bOurBufferConnected = true;
|
||||
|
||||
@@ -225,7 +219,7 @@ void CCursorManager::tickAnimatedCursor() {
|
||||
if ((size_t)m_iCurrentAnimationFrame >= m_sCurrentCursorShapeData.images.size())
|
||||
m_iCurrentAnimationFrame = 0;
|
||||
|
||||
m_vCursorBuffers.emplace_back(std::make_unique<CCursorBuffer>(
|
||||
m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>(
|
||||
m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].surface,
|
||||
Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size},
|
||||
Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY}));
|
||||
@@ -256,10 +250,9 @@ void CCursorManager::setXWaylandCursor() {
|
||||
if (CURSOR.surface) {
|
||||
g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size},
|
||||
{CURSOR.hotspotX, CURSOR.hotspotY});
|
||||
} else if (const auto XCURSOR = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, "left_ptr", 1); XCURSOR) {
|
||||
g_pXWayland->setCursor(XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, {(int)XCURSOR->images[0]->width, (int)XCURSOR->images[0]->height},
|
||||
{(double)XCURSOR->images[0]->hotspot_x, (double)XCURSOR->images[0]->hotspot_y});
|
||||
} else
|
||||
} else if (xcursor.themeLoaded)
|
||||
g_pXWayland->setCursor((uint8_t*)xcursor.defaultCursor->pixels.data(), xcursor.defaultCursor->size.x * 4, xcursor.defaultCursor->size, xcursor.defaultCursor->hotspot);
|
||||
else
|
||||
Debug::log(ERR, "CursorManager: no valid cursor for xwayland");
|
||||
}
|
||||
|
||||
@@ -284,7 +277,7 @@ void CCursorManager::updateTheme() {
|
||||
|
||||
for (auto& m : g_pCompositor->m_vMonitors) {
|
||||
m->forceFullFrames = 5;
|
||||
g_pCompositor->scheduleFrameForMonitor(m.get());
|
||||
g_pCompositor->scheduleFrameForMonitor(m.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,37 +296,163 @@ bool CCursorManager::changeTheme(const std::string& name, const int size) {
|
||||
|
||||
Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", name);
|
||||
|
||||
if (m_pWLRXCursorMgr)
|
||||
wlr_xcursor_manager_destroy(m_pWLRXCursorMgr);
|
||||
xcursor.loadTheme(name, size);
|
||||
|
||||
m_pWLRXCursorMgr = wlr_xcursor_manager_create(name.empty() ? "" : name.c_str(), size);
|
||||
bool xSuccess = wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0) == 1;
|
||||
m_szTheme = name;
|
||||
m_iSize = size;
|
||||
updateTheme();
|
||||
return true;
|
||||
}
|
||||
|
||||
// this basically checks if xcursor changed used theme to default but better
|
||||
bool diffTheme = false;
|
||||
wlr_xcursor_manager_theme* theme;
|
||||
wl_list_for_each(theme, &m_pWLRXCursorMgr->scaled_themes, link) {
|
||||
if (std::string{theme->theme->name} != name) {
|
||||
diffTheme = true;
|
||||
break;
|
||||
// Taken from https://gitlab.freedesktop.org/xorg/lib/libxcursor/-/blob/master/src/library.c
|
||||
// however modified to fit wayland cursor shape names better.
|
||||
// _ -> -
|
||||
// clang-format off
|
||||
static std::array<const char*, 77> XCURSOR_STANDARD_NAMES = {
|
||||
"X_cursor",
|
||||
"default", // arrow
|
||||
"ns-resize", // based-arrow-down
|
||||
"ns-resize", // based-arrow-up
|
||||
"boat",
|
||||
"bogosity",
|
||||
"sw-resize", // bottom-left-corner
|
||||
"se-resize", // bottom-right-corner
|
||||
"s-resize", // bottom-side
|
||||
"bottom-tee",
|
||||
"box-spiral",
|
||||
"center-ptr",
|
||||
"circle",
|
||||
"clock",
|
||||
"coffee-mug",
|
||||
"cross",
|
||||
"cross-reverse",
|
||||
"crosshair",
|
||||
"diamond-cross",
|
||||
"dot",
|
||||
"dotbox",
|
||||
"double-arrow",
|
||||
"draft-large",
|
||||
"draft-small",
|
||||
"draped-box",
|
||||
"exchange",
|
||||
"move", // fleur
|
||||
"gobbler",
|
||||
"gumby",
|
||||
"pointer", // hand1
|
||||
"grabbing", // hand2
|
||||
"heart",
|
||||
"icon",
|
||||
"iron-cross",
|
||||
"default", // left-ptr
|
||||
"w-resize", // left-side
|
||||
"left-tee",
|
||||
"leftbutton",
|
||||
"ll-angle",
|
||||
"lr-angle",
|
||||
"man",
|
||||
"middlebutton",
|
||||
"mouse",
|
||||
"pencil",
|
||||
"pirate",
|
||||
"plus",
|
||||
"help", // question-arrow
|
||||
"right-ptr",
|
||||
"e-resize", // right-side
|
||||
"right-tee",
|
||||
"rightbutton",
|
||||
"rtl-logo",
|
||||
"sailboat",
|
||||
"ns-resize", // sb-down-arrow
|
||||
"ew-resize", // sb-h-double-arrow
|
||||
"ew-resize", // sb-left-arrow
|
||||
"ew-resize", // sb-right-arrow
|
||||
"n-resize", // sb-up-arrow
|
||||
"s-resize", // sb-v-double-arrow
|
||||
"shuttle",
|
||||
"sizing",
|
||||
"spider",
|
||||
"spraycan",
|
||||
"star",
|
||||
"target",
|
||||
"cell", // tcross
|
||||
"nw-resize", // top-left-arrow
|
||||
"nw-resize", // top-left-corner
|
||||
"ne-resize", // top-right-corner
|
||||
"n-resize", // top-side
|
||||
"top-tee",
|
||||
"trek",
|
||||
"ul-angle",
|
||||
"umbrella",
|
||||
"ur-angle",
|
||||
"wait", // watch
|
||||
"text", // xterm
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
void CCursorManager::SXCursorManager::loadTheme(const std::string& name, int size) {
|
||||
if (lastLoadSize == size && themeName == name)
|
||||
return;
|
||||
|
||||
lastLoadSize = size;
|
||||
themeLoaded = false;
|
||||
themeName = name.empty() ? "default" : name;
|
||||
|
||||
auto img = XcursorShapeLoadImage(2, themeName.c_str(), size);
|
||||
|
||||
if (!img) {
|
||||
Debug::log(ERR, "XCursor failed finding theme \"{}\". Trying size 24.", themeName);
|
||||
size = 24;
|
||||
img = XcursorShapeLoadImage(2, themeName.c_str(), size);
|
||||
if (!img) {
|
||||
Debug::log(ERR, "XCursor failed finding theme \"{}\".", themeName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (xSuccess && !diffTheme) {
|
||||
m_szTheme = name;
|
||||
m_iSize = size;
|
||||
updateTheme();
|
||||
return true;
|
||||
defaultCursor = makeShared<SXCursor>();
|
||||
defaultCursor->size = {(int)img->width, (int)img->height};
|
||||
defaultCursor->hotspot = {(int)img->xhot, (int)img->yhot};
|
||||
|
||||
defaultCursor->pixels.resize(img->width * img->height);
|
||||
std::memcpy(defaultCursor->pixels.data(), img->pixels, img->width * img->height * sizeof(uint32_t));
|
||||
|
||||
themeLoaded = true;
|
||||
|
||||
XcursorImageDestroy(img);
|
||||
|
||||
// gather as many shapes as we can find.
|
||||
cursors.clear();
|
||||
|
||||
for (auto& shape : CURSOR_SHAPE_NAMES) {
|
||||
int id = -1;
|
||||
for (size_t i = 0; i < XCURSOR_STANDARD_NAMES.size(); ++i) {
|
||||
if (XCURSOR_STANDARD_NAMES.at(i) == std::string{shape}) {
|
||||
id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (id < 0) {
|
||||
Debug::log(LOG, "XCursor has no shape {}, skipping", shape);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto xImage = XcursorShapeLoadImage(id << 1 /* wtf xcursor? */, themeName.c_str(), size);
|
||||
|
||||
if (!xImage) {
|
||||
Debug::log(LOG, "XCursor failed to find a shape with name {}, skipping", shape);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto xcursor = makeShared<SXCursor>();
|
||||
xcursor->size = {(int)xImage->width, (int)xImage->height};
|
||||
xcursor->hotspot = {(int)xImage->xhot, (int)xImage->yhot};
|
||||
|
||||
xcursor->pixels.resize(xImage->width * xImage->height);
|
||||
std::memcpy(xcursor->pixels.data(), xImage->pixels, xImage->width * xImage->height * sizeof(uint32_t));
|
||||
|
||||
cursors.emplace(std::string{shape}, xcursor);
|
||||
|
||||
XcursorImageDestroy(xImage);
|
||||
}
|
||||
|
||||
Debug::log(ERR, "X also failed loading theme \"{}\", falling back to previous theme.", name);
|
||||
|
||||
m_pHyprcursor = std::make_unique<Hyprcursor::CHyprcursorManager>(m_szTheme.c_str(), hcLogger);
|
||||
|
||||
wlr_xcursor_manager_destroy(m_pWLRXCursorMgr);
|
||||
m_pWLRXCursorMgr = wlr_xcursor_manager_create(m_szTheme.c_str(), m_iSize);
|
||||
wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0);
|
||||
|
||||
updateTheme();
|
||||
return false;
|
||||
}
|
||||
|
Reference in New Issue
Block a user