Core: More work to get Hyprland working

This commit is contained in:
Vaxry 2024-06-20 19:24:43 +02:00
parent a13f03d718
commit a7a8840400
7 changed files with 247 additions and 91 deletions

View file

@ -54,11 +54,18 @@ namespace Aquamarine {
virtual ~IBackendImplementation() { virtual ~IBackendImplementation() {
; ;
} }
enum eBackendCapabilities : uint32_t {
AQ_BACKEND_CAPABILITY_POINTER = (1 << 0),
};
virtual eBackendType type() = 0; virtual eBackendType type() = 0;
virtual bool start() = 0; virtual bool start() = 0;
virtual int pollFD() = 0; virtual int pollFD() = 0;
virtual int drmFD() = 0; virtual int drmFD() = 0;
virtual bool dispatchEvents() = 0; virtual bool dispatchEvents() = 0;
virtual uint32_t capabilities() = 0;
virtual void onReady() = 0;
}; };
class CBackend { class CBackend {
@ -74,9 +81,21 @@ namespace Aquamarine {
void log(eBackendLogLevel level, const std::string& msg); void log(eBackendLogLevel level, const std::string& msg);
/* Enters the event loop synchronously. For simple clients, this is probably what you want. For more complex ones, /* Enters the event loop synchronously. For simple clients, this is probably what you want. For more complex ones,
see async methods further below */ see the async methods further below */
void enterLoop(); void enterLoop();
/* Gets all the FDs you have to poll. When any single one fires, call dispatchEventsAsync */
std::vector<int> getPollFDs();
/* Dispatches all pending events on all queues then returns */
void dispatchEventsAsync();
/* Checks if the backend has a session - iow if it's a DRM backend */
bool hasSession();
/* Get the primary DRM FD */
int drmFD();
struct { struct {
Hyprutils::Signal::CSignal newOutput; Hyprutils::Signal::CSignal newOutput;
Hyprutils::Signal::CSignal newPointer; Hyprutils::Signal::CSignal newPointer;

View file

@ -26,7 +26,7 @@ namespace Aquamarine {
private: private:
struct { struct {
Hyprutils::Memory::CSharedPointer<CWlBuffer> buffer; Hyprutils::Memory::CSharedPointer<CCWlBuffer> buffer;
} waylandState; } waylandState;
Hyprutils::Memory::CWeakPointer<IBuffer> buffer; Hyprutils::Memory::CWeakPointer<IBuffer> buffer;
@ -39,11 +39,17 @@ namespace Aquamarine {
public: public:
virtual ~CWaylandOutput(); virtual ~CWaylandOutput();
virtual bool commit(); virtual bool commit();
virtual bool test();
virtual Hyprutils::Memory::CSharedPointer<IBackendImplementation> getBackend();
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
virtual void moveCursor(const Hyprutils::Math::Vector2D& coord);
virtual void scheduleFrame();
Hyprutils::Memory::CWeakPointer<CWaylandOutput> self;
private: private:
CWaylandOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_); CWaylandOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_);
std::string name;
Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend; Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend;
Hyprutils::Memory::CSharedPointer<CWaylandBuffer> wlBufferFromBuffer(Hyprutils::Memory::CSharedPointer<IBuffer> buffer); Hyprutils::Memory::CSharedPointer<CWaylandBuffer> wlBufferFromBuffer(Hyprutils::Memory::CSharedPointer<IBuffer> buffer);
@ -55,10 +61,10 @@ namespace Aquamarine {
} backendState; } backendState;
struct { struct {
Hyprutils::Memory::CSharedPointer<CWlSurface> surface; Hyprutils::Memory::CSharedPointer<CCWlSurface> surface;
Hyprutils::Memory::CSharedPointer<CXdgSurface> xdgSurface; Hyprutils::Memory::CSharedPointer<CCXdgSurface> xdgSurface;
Hyprutils::Memory::CSharedPointer<CXdgToplevel> xdgToplevel; Hyprutils::Memory::CSharedPointer<CCXdgToplevel> xdgToplevel;
Hyprutils::Memory::CSharedPointer<CWlCallback> frameCallback; Hyprutils::Memory::CSharedPointer<CCWlCallback> frameCallback;
} waylandState; } waylandState;
friend class CWaylandBackend; friend class CWaylandBackend;
@ -67,12 +73,12 @@ namespace Aquamarine {
class CWaylandKeyboard : public IKeyboard { class CWaylandKeyboard : public IKeyboard {
public: public:
CWaylandKeyboard(Hyprutils::Memory::CSharedPointer<CWlKeyboard> keyboard_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_); CWaylandKeyboard(Hyprutils::Memory::CSharedPointer<CCWlKeyboard> keyboard_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_);
virtual ~CWaylandKeyboard(); virtual ~CWaylandKeyboard();
virtual const std::string& getName(); virtual const std::string& getName();
Hyprutils::Memory::CSharedPointer<CWlKeyboard> keyboard; Hyprutils::Memory::CSharedPointer<CCWlKeyboard> keyboard;
Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend; Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend;
private: private:
@ -81,12 +87,12 @@ namespace Aquamarine {
class CWaylandPointer : public IPointer { class CWaylandPointer : public IPointer {
public: public:
CWaylandPointer(Hyprutils::Memory::CSharedPointer<CWlPointer> pointer_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_); CWaylandPointer(Hyprutils::Memory::CSharedPointer<CCWlPointer> pointer_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_);
virtual ~CWaylandPointer(); virtual ~CWaylandPointer();
virtual const std::string& getName(); virtual const std::string& getName();
Hyprutils::Memory::CSharedPointer<CWlPointer> pointer; Hyprutils::Memory::CSharedPointer<CCWlPointer> pointer;
Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend; Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend;
private: private:
@ -101,6 +107,9 @@ namespace Aquamarine {
virtual int pollFD(); virtual int pollFD();
virtual int drmFD(); virtual int drmFD();
virtual bool dispatchEvents(); virtual bool dispatchEvents();
virtual uint32_t capabilities();
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
virtual void onReady();
Hyprutils::Memory::CWeakPointer<CWaylandBackend> self; Hyprutils::Memory::CWeakPointer<CWaylandBackend> self;
@ -114,7 +123,7 @@ namespace Aquamarine {
// //
Hyprutils::Memory::CWeakPointer<CBackend> backend; Hyprutils::Memory::CWeakPointer<CBackend> backend;
std::vector<Hyprutils::Memory::CSharedPointer<CWaylandOutput>> outputs; std::vector<Hyprutils::Memory::CSharedPointer<CWaylandOutput>> outputs, scheduledFrames;
std::vector<Hyprutils::Memory::CSharedPointer<CWaylandKeyboard>> keyboards; std::vector<Hyprutils::Memory::CSharedPointer<CWaylandKeyboard>> keyboards;
std::vector<Hyprutils::Memory::CSharedPointer<CWaylandPointer>> pointers; std::vector<Hyprutils::Memory::CSharedPointer<CWaylandPointer>> pointers;
@ -126,12 +135,12 @@ namespace Aquamarine {
wl_display* display = nullptr; wl_display* display = nullptr;
// hw-s types // hw-s types
Hyprutils::Memory::CSharedPointer<CWlRegistry> registry; Hyprutils::Memory::CSharedPointer<CCWlRegistry> registry;
Hyprutils::Memory::CSharedPointer<CWlSeat> seat; Hyprutils::Memory::CSharedPointer<CCWlSeat> seat;
Hyprutils::Memory::CSharedPointer<CXdgWmBase> xdg; Hyprutils::Memory::CSharedPointer<CCXdgWmBase> xdg;
Hyprutils::Memory::CSharedPointer<CWlCompositor> compositor; Hyprutils::Memory::CSharedPointer<CCWlCompositor> compositor;
Hyprutils::Memory::CSharedPointer<CZwpLinuxDmabufV1> dmabuf; Hyprutils::Memory::CSharedPointer<CCZwpLinuxDmabufV1> dmabuf;
Hyprutils::Memory::CSharedPointer<CZwpLinuxDmabufFeedbackV1> dmabufFeedback; Hyprutils::Memory::CSharedPointer<CCZwpLinuxDmabufFeedbackV1> dmabufFeedback;
// control // control
bool dmabufFailed = false; bool dmabufFailed = false;

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include <optional>
#include <hyprutils/signal/Signal.hpp> #include <hyprutils/signal/Signal.hpp>
#include <hyprutils/memory/SharedPtr.hpp> #include <hyprutils/memory/SharedPtr.hpp>
#include <hyprutils/math/Region.hpp> #include <hyprutils/math/Region.hpp>
@ -9,6 +10,9 @@
#include "../buffer/Buffer.hpp" #include "../buffer/Buffer.hpp"
namespace Aquamarine { namespace Aquamarine {
class IBackendImplementation;
struct SOutputMode { struct SOutputMode {
Hyprutils::Math::Vector2D pixelSize; Hyprutils::Math::Vector2D pixelSize;
unsigned int refreshRate = 0 /* in mHz */; unsigned int refreshRate = 0 /* in mHz */;
@ -20,10 +24,20 @@ namespace Aquamarine {
AQ_OUTPUT_PRESENTATION_IMMEDIATE, // likely tearing AQ_OUTPUT_PRESENTATION_IMMEDIATE, // likely tearing
}; };
enum eSubpixelMode {
AQ_SUBPIXEL_UNKNOWN = 0,
AQ_SUBPIXEL_NONE,
AQ_SUBPIXEL_HORIZONTAL_RGB,
AQ_SUBPIXEL_HORIZONTAL_BGR,
AQ_SUBPIXEL_VERTICAL_RGB,
AQ_SUBPIXEL_VERTICAL_BGR,
};
class IOutput; class IOutput;
class COutputState { class COutputState {
public: public:
// TODO: make this state private, this sucks
Hyprutils::Math::CRegion damage; Hyprutils::Math::CRegion damage;
bool enabled = false; bool enabled = false;
bool adaptiveSync = false; bool adaptiveSync = false;
@ -31,7 +45,7 @@ namespace Aquamarine {
std::vector<uint16_t> gammaLut; std::vector<uint16_t> gammaLut;
Hyprutils::Math::Vector2D lastModeSize; Hyprutils::Math::Vector2D lastModeSize;
Hyprutils::Memory::CWeakPointer<SOutputMode> mode; Hyprutils::Memory::CWeakPointer<SOutputMode> mode;
std::optional<SOutputMode> customMode; Hyprutils::Memory::CSharedPointer<SOutputMode> customMode;
uint32_t drmFormat = DRM_FORMAT_INVALID; uint32_t drmFormat = DRM_FORMAT_INVALID;
Hyprutils::Memory::CSharedPointer<IBuffer> buffer; Hyprutils::Memory::CSharedPointer<IBuffer> buffer;
}; };
@ -43,12 +57,19 @@ namespace Aquamarine {
} }
virtual bool commit() = 0; virtual bool commit() = 0;
virtual bool test() = 0;
virtual Hyprutils::Memory::CSharedPointer<IBackendImplementation> getBackend() = 0;
virtual Hyprutils::Memory::CSharedPointer<SOutputMode> preferredMode();
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
virtual void moveCursor(const Hyprutils::Math::Vector2D& coord); // includes the hotspot
virtual void scheduleFrame();
std::string name, description, make, model, serial; std::string name, description, make, model, serial;
Hyprutils::Math::Vector2D physicalSize; Hyprutils::Math::Vector2D physicalSize;
bool enabled = false; bool enabled = false;
bool adaptiveSync = false; bool adaptiveSync = false;
bool nonDesktop = false; bool nonDesktop = false;
eSubpixelMode subpixel = AQ_SUBPIXEL_NONE;
// //
std::vector<Hyprutils::Memory::CSharedPointer<SOutputMode>> modes; std::vector<Hyprutils::Memory::CSharedPointer<SOutputMode>> modes;

View file

@ -103,6 +103,10 @@ bool Aquamarine::CBackend::start() {
if (!allocator) if (!allocator)
return false; return false;
for (auto& b : implementations) {
b->onReady();
}
return true; return true;
} }
@ -167,8 +171,41 @@ void Aquamarine::CBackend::enterLoop() {
std::lock_guard<std::mutex> lg(m_sEventLoopInternals.eventLock); std::lock_guard<std::mutex> lg(m_sEventLoopInternals.eventLock);
for (size_t i = 0; i < pollFDs.size(); ++i) { dispatchEventsAsync();
implementations.at(i)->dispatchEvents();
}
} }
} }
std::vector<int> Aquamarine::CBackend::getPollFDs() {
std::vector<int> result;
for (auto& i : implementations) {
int fd = i->pollFD();
if (fd < 0)
continue;
result.push_back(fd);
}
return result;
}
int Aquamarine::CBackend::drmFD() {
for (auto& i : implementations) {
int fd = i->drmFD();
if (fd < 0)
continue;
return fd;
}
return -1;
}
void Aquamarine::CBackend::dispatchEventsAsync() {
for (auto& i : implementations) {
i->dispatchEvents();
}
}
bool Aquamarine::CBackend::hasSession() {
// TODO:
return false;
}

View file

@ -35,37 +35,37 @@ bool Aquamarine::CWaylandBackend::start() {
return false; return false;
} }
waylandState.registry = makeShared<CWlRegistry>((wl_proxy*)wl_display_get_registry(waylandState.display)); waylandState.registry = makeShared<CCWlRegistry>((wl_proxy*)wl_display_get_registry(waylandState.display));
backend->log(AQ_LOG_DEBUG, std::format("Got registry at 0x{:x}", (uintptr_t)waylandState.registry->resource())); backend->log(AQ_LOG_DEBUG, std::format("Got registry at 0x{:x}", (uintptr_t)waylandState.registry->resource()));
waylandState.registry->setGlobal([this](CWlRegistry* r, uint32_t id, const char* name, uint32_t version) { waylandState.registry->setGlobal([this](CCWlRegistry* r, uint32_t id, const char* name, uint32_t version) {
backend->log(AQ_LOG_TRACE, std::format(" | received global: {} (version {}) with id {}", name, version, id)); backend->log(AQ_LOG_TRACE, std::format(" | received global: {} (version {}) with id {}", name, version, id));
const std::string NAME = name; const std::string NAME = name;
if (NAME == "wl_seat") { if (NAME == "wl_seat") {
backend->log(AQ_LOG_TRACE, std::format(" > binding to global: {} (version {}) with id {}", name, 9, id)); backend->log(AQ_LOG_TRACE, std::format(" > binding to global: {} (version {}) with id {}", name, 9, id));
waylandState.seat = makeShared<CWlSeat>((wl_proxy*)wl_registry_bind((wl_registry*)waylandState.registry->resource(), id, &wl_seat_interface, 9)); waylandState.seat = makeShared<CCWlSeat>((wl_proxy*)wl_registry_bind((wl_registry*)waylandState.registry->resource(), id, &wl_seat_interface, 9));
initSeat(); initSeat();
} else if (NAME == "xdg_wm_base") { } else if (NAME == "xdg_wm_base") {
backend->log(AQ_LOG_TRACE, std::format(" > binding to global: {} (version {}) with id {}", name, 6, id)); backend->log(AQ_LOG_TRACE, std::format(" > binding to global: {} (version {}) with id {}", name, 6, id));
waylandState.xdg = makeShared<CXdgWmBase>((wl_proxy*)wl_registry_bind((wl_registry*)waylandState.registry->resource(), id, &xdg_wm_base_interface, 6)); waylandState.xdg = makeShared<CCXdgWmBase>((wl_proxy*)wl_registry_bind((wl_registry*)waylandState.registry->resource(), id, &xdg_wm_base_interface, 6));
initShell(); initShell();
} else if (NAME == "wl_compositor") { } else if (NAME == "wl_compositor") {
backend->log(AQ_LOG_TRACE, std::format(" > binding to global: {} (version {}) with id {}", name, 6, id)); backend->log(AQ_LOG_TRACE, std::format(" > binding to global: {} (version {}) with id {}", name, 6, id));
waylandState.compositor = makeShared<CWlCompositor>((wl_proxy*)wl_registry_bind((wl_registry*)waylandState.registry->resource(), id, &wl_compositor_interface, 6)); waylandState.compositor = makeShared<CCWlCompositor>((wl_proxy*)wl_registry_bind((wl_registry*)waylandState.registry->resource(), id, &wl_compositor_interface, 6));
} else if (NAME == "zwp_linux_dmabuf_v1") { } else if (NAME == "zwp_linux_dmabuf_v1") {
backend->log(AQ_LOG_TRACE, std::format(" > binding to global: {} (version {}) with id {}", name, 5, id)); backend->log(AQ_LOG_TRACE, std::format(" > binding to global: {} (version {}) with id {}", name, 5, id));
waylandState.dmabuf = waylandState.dmabuf =
makeShared<CZwpLinuxDmabufV1>((wl_proxy*)wl_registry_bind((wl_registry*)waylandState.registry->resource(), id, &zwp_linux_dmabuf_v1_interface, 5)); makeShared<CCZwpLinuxDmabufV1>((wl_proxy*)wl_registry_bind((wl_registry*)waylandState.registry->resource(), id, &zwp_linux_dmabuf_v1_interface, 5));
if (!initDmabuf()) { if (!initDmabuf()) {
backend->log(AQ_LOG_ERROR, "Wayland backend cannot start: zwp_linux_dmabuf_v1 init failed"); backend->log(AQ_LOG_ERROR, "Wayland backend cannot start: zwp_linux_dmabuf_v1 init failed");
waylandState.dmabufFailed = true; waylandState.dmabufFailed = true;
} }
} }
}); });
waylandState.registry->setGlobalRemove([this](CWlRegistry* r, uint32_t id) { ; }); waylandState.registry->setGlobalRemove([this](CCWlRegistry* r, uint32_t id) { backend->log(AQ_LOG_DEBUG, std::format("Global {} removed", id)); });
wl_display_roundtrip(waylandState.display); wl_display_roundtrip(waylandState.display);
@ -87,6 +87,7 @@ int Aquamarine::CWaylandBackend::drmFD() {
void Aquamarine::CWaylandBackend::createOutput(const std::string& szName) { void Aquamarine::CWaylandBackend::createOutput(const std::string& szName) {
auto o = outputs.emplace_back(SP<CWaylandOutput>(new CWaylandOutput(szName, self))); auto o = outputs.emplace_back(SP<CWaylandOutput>(new CWaylandOutput(szName, self)));
o->self = o;
backend->events.newOutput.emit(SP<IOutput>(o)); backend->events.newOutput.emit(SP<IOutput>(o));
} }
@ -112,16 +113,42 @@ bool Aquamarine::CWaylandBackend::dispatchEvents() {
wl_display_flush(waylandState.display); wl_display_flush(waylandState.display);
} while (ret > 0); } while (ret > 0);
// dispatch frames
for (auto& f : scheduledFrames) {
f->events.frame.emit();
}
scheduledFrames.clear();
return true; return true;
} }
Aquamarine::CWaylandKeyboard::CWaylandKeyboard(SP<CWlKeyboard> keyboard_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_) : keyboard(keyboard_), backend(backend_) { uint32_t Aquamarine::CWaylandBackend::capabilities() {
return AQ_BACKEND_CAPABILITY_POINTER;
}
bool Aquamarine::CWaylandBackend::setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot) {
// TODO:
return true;
}
void Aquamarine::CWaylandBackend::onReady() {
for (auto& o : outputs) {
o->swapchain = makeShared<CSwapchain>(backend->allocator);
if (!o->swapchain) {
backend->log(AQ_LOG_ERROR, std::format("Output {} failed: swapchain creation failed", o->name));
continue;
}
}
}
Aquamarine::CWaylandKeyboard::CWaylandKeyboard(SP<CCWlKeyboard> keyboard_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_) : keyboard(keyboard_), backend(backend_) {
if (!keyboard->resource()) if (!keyboard->resource())
return; return;
backend->backend->log(AQ_LOG_DEBUG, "New wayland keyboard wl_keyboard"); backend->backend->log(AQ_LOG_DEBUG, "New wayland keyboard wl_keyboard");
keyboard->setKey([this](CWlKeyboard* r, uint32_t serial, uint32_t timeMs, uint32_t key, wl_keyboard_key_state state) { keyboard->setKey([this](CCWlKeyboard* r, uint32_t serial, uint32_t timeMs, uint32_t key, wl_keyboard_key_state state) {
events.key.emit(SKeyEvent{ events.key.emit(SKeyEvent{
.timeMs = timeMs, .timeMs = timeMs,
.key = key, .key = key,
@ -129,7 +156,7 @@ Aquamarine::CWaylandKeyboard::CWaylandKeyboard(SP<CWlKeyboard> keyboard_, Hyprut
}); });
}); });
keyboard->setModifiers([this](CWlKeyboard* r, uint32_t serial, uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { keyboard->setModifiers([this](CCWlKeyboard* r, uint32_t serial, uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) {
events.modifiers.emit(SModifiersEvent{ events.modifiers.emit(SModifiersEvent{
.depressed = depressed, .depressed = depressed,
.latched = latched, .latched = latched,
@ -147,18 +174,17 @@ const std::string& Aquamarine::CWaylandKeyboard::getName() {
return name; return name;
} }
Aquamarine::CWaylandPointer::CWaylandPointer(SP<CWlPointer> pointer_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_) : pointer(pointer_), backend(backend_) { Aquamarine::CWaylandPointer::CWaylandPointer(SP<CCWlPointer> pointer_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_) : pointer(pointer_), backend(backend_) {
if (!pointer->resource()) if (!pointer->resource())
return; return;
backend->backend->log(AQ_LOG_DEBUG, "New wayland pointer wl_pointer"); backend->backend->log(AQ_LOG_DEBUG, "New wayland pointer wl_pointer");
pointer->setMotion([this](CWlPointer* r, uint32_t serial, wl_fixed_t x, wl_fixed_t y) { pointer->setMotion([this](CCWlPointer* r, uint32_t serial, wl_fixed_t x, wl_fixed_t y) {
if (!backend->focusedOutput || (!backend->focusedOutput->state->mode && !backend->focusedOutput->state->customMode.has_value())) if (!backend->focusedOutput || (!backend->focusedOutput->state->mode && !backend->focusedOutput->state->customMode))
return; return;
const Vector2D size = const Vector2D size = backend->focusedOutput->state->customMode ? backend->focusedOutput->state->customMode->pixelSize : backend->focusedOutput->state->mode->pixelSize;
backend->focusedOutput->state->customMode.has_value() ? backend->focusedOutput->state->customMode->pixelSize : backend->focusedOutput->state->mode->pixelSize;
Vector2D local = {wl_fixed_to_double(x), wl_fixed_to_double(y)}; Vector2D local = {wl_fixed_to_double(x), wl_fixed_to_double(y)};
local = local / size; local = local / size;
@ -168,7 +194,7 @@ Aquamarine::CWaylandPointer::CWaylandPointer(SP<CWlPointer> pointer_, Hyprutils:
}); });
}); });
pointer->setEnter([this](CWlPointer* r, uint32_t serial, wl_proxy* surface, wl_fixed_t x, wl_fixed_t y) { pointer->setEnter([this](CCWlPointer* r, uint32_t serial, wl_proxy* surface, wl_fixed_t x, wl_fixed_t y) {
backend->lastEnterSerial = serial; backend->lastEnterSerial = serial;
for (auto& o : backend->outputs) { for (auto& o : backend->outputs) {
@ -181,7 +207,7 @@ Aquamarine::CWaylandPointer::CWaylandPointer(SP<CWlPointer> pointer_, Hyprutils:
} }
}); });
pointer->setButton([this](CWlPointer* r, uint32_t serial, uint32_t timeMs, uint32_t button, wl_pointer_button_state state) { pointer->setButton([this](CCWlPointer* r, uint32_t serial, uint32_t timeMs, uint32_t button, wl_pointer_button_state state) {
events.button.emit(SButtonEvent{ events.button.emit(SButtonEvent{
.timeMs = timeMs, .timeMs = timeMs,
.button = button, .button = button,
@ -189,7 +215,7 @@ Aquamarine::CWaylandPointer::CWaylandPointer(SP<CWlPointer> pointer_, Hyprutils:
}); });
}); });
pointer->setAxis([this](CWlPointer* r, uint32_t timeMs, wl_pointer_axis axis, wl_fixed_t value) { pointer->setAxis([this](CCWlPointer* r, uint32_t timeMs, wl_pointer_axis axis, wl_fixed_t value) {
events.axis.emit(SAxisEvent{ events.axis.emit(SAxisEvent{
.timeMs = timeMs, .timeMs = timeMs,
.axis = axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL ? AQ_POINTER_AXIS_HORIZONTAL : AQ_POINTER_AXIS_VERTICAL, .axis = axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL ? AQ_POINTER_AXIS_HORIZONTAL : AQ_POINTER_AXIS_VERTICAL,
@ -197,7 +223,7 @@ Aquamarine::CWaylandPointer::CWaylandPointer(SP<CWlPointer> pointer_, Hyprutils:
}); });
}); });
pointer->setFrame([this](CWlPointer* r) { events.frame.emit(); }); pointer->setFrame([this](CCWlPointer* r) { events.frame.emit(); });
} }
Aquamarine::CWaylandPointer::~CWaylandPointer() { Aquamarine::CWaylandPointer::~CWaylandPointer() {
@ -209,18 +235,18 @@ const std::string& Aquamarine::CWaylandPointer::getName() {
} }
void Aquamarine::CWaylandBackend::initSeat() { void Aquamarine::CWaylandBackend::initSeat() {
waylandState.seat->setCapabilities([this](CWlSeat* r, wl_seat_capability cap) { waylandState.seat->setCapabilities([this](CCWlSeat* r, wl_seat_capability cap) {
const bool HAS_KEYBOARD = ((uint32_t)cap) & WL_SEAT_CAPABILITY_KEYBOARD; const bool HAS_KEYBOARD = ((uint32_t)cap) & WL_SEAT_CAPABILITY_KEYBOARD;
const bool HAS_POINTER = ((uint32_t)cap) & WL_SEAT_CAPABILITY_POINTER; const bool HAS_POINTER = ((uint32_t)cap) & WL_SEAT_CAPABILITY_POINTER;
if (HAS_KEYBOARD && keyboards.empty()) { if (HAS_KEYBOARD && keyboards.empty()) {
auto k = keyboards.emplace_back(makeShared<CWaylandKeyboard>(makeShared<CWlKeyboard>(waylandState.seat->sendGetKeyboard()), self)); auto k = keyboards.emplace_back(makeShared<CWaylandKeyboard>(makeShared<CCWlKeyboard>(waylandState.seat->sendGetKeyboard()), self));
backend->events.newKeyboard.emit(SP<IKeyboard>(k)); backend->events.newKeyboard.emit(SP<IKeyboard>(k));
} else if (!HAS_KEYBOARD && !keyboards.empty()) } else if (!HAS_KEYBOARD && !keyboards.empty())
keyboards.clear(); keyboards.clear();
if (HAS_POINTER && pointers.empty()) { if (HAS_POINTER && pointers.empty()) {
auto p = pointers.emplace_back(makeShared<CWaylandPointer>(makeShared<CWlPointer>(waylandState.seat->sendGetPointer()), self)); auto p = pointers.emplace_back(makeShared<CWaylandPointer>(makeShared<CCWlPointer>(waylandState.seat->sendGetPointer()), self));
backend->events.newPointer.emit(SP<IPointer>(p)); backend->events.newPointer.emit(SP<IPointer>(p));
} else if (!HAS_POINTER && !pointers.empty()) } else if (!HAS_POINTER && !pointers.empty())
pointers.clear(); pointers.clear();
@ -228,22 +254,22 @@ void Aquamarine::CWaylandBackend::initSeat() {
} }
void Aquamarine::CWaylandBackend::initShell() { void Aquamarine::CWaylandBackend::initShell() {
waylandState.xdg->setPing([](CXdgWmBase* r, uint32_t serial) { r->sendPong(serial); }); waylandState.xdg->setPing([](CCXdgWmBase* r, uint32_t serial) { r->sendPong(serial); });
} }
bool Aquamarine::CWaylandBackend::initDmabuf() { bool Aquamarine::CWaylandBackend::initDmabuf() {
waylandState.dmabufFeedback = makeShared<CZwpLinuxDmabufFeedbackV1>(waylandState.dmabuf->sendGetDefaultFeedback()); waylandState.dmabufFeedback = makeShared<CCZwpLinuxDmabufFeedbackV1>(waylandState.dmabuf->sendGetDefaultFeedback());
if (!waylandState.dmabufFeedback) { if (!waylandState.dmabufFeedback) {
backend->log(AQ_LOG_ERROR, "initDmabuf: failed to get default feedback"); backend->log(AQ_LOG_ERROR, "initDmabuf: failed to get default feedback");
return false; return false;
} }
waylandState.dmabufFeedback->setDone([this](CZwpLinuxDmabufFeedbackV1* r) { waylandState.dmabufFeedback->setDone([this](CCZwpLinuxDmabufFeedbackV1* r) {
// no-op // no-op
backend->log(AQ_LOG_DEBUG, "zwp_linux_dmabuf_v1: Got done"); backend->log(AQ_LOG_DEBUG, "zwp_linux_dmabuf_v1: Got done");
}); });
waylandState.dmabufFeedback->setMainDevice([this](CZwpLinuxDmabufFeedbackV1* r, wl_array* deviceArr) { waylandState.dmabufFeedback->setMainDevice([this](CCZwpLinuxDmabufFeedbackV1* r, wl_array* deviceArr) {
backend->log(AQ_LOG_DEBUG, "zwp_linux_dmabuf_v1: Got main device"); backend->log(AQ_LOG_DEBUG, "zwp_linux_dmabuf_v1: Got main device");
dev_t device; dev_t device;
@ -296,29 +322,29 @@ bool Aquamarine::CWaylandBackend::initDmabuf() {
return true; return true;
} }
Aquamarine::CWaylandOutput::CWaylandOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_) : name(name_), backend(backend_) { Aquamarine::CWaylandOutput::CWaylandOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_) : backend(backend_) {
errno = 0; name = name_;
waylandState.surface = makeShared<CWlSurface>(backend->waylandState.compositor->sendCreateSurface()); waylandState.surface = makeShared<CCWlSurface>(backend->waylandState.compositor->sendCreateSurface());
if (!waylandState.surface->resource()) { if (!waylandState.surface->resource()) {
backend->backend->log(AQ_LOG_ERROR, std::format("Output {} failed: no surface given. Errno: {}", name, errno)); backend->backend->log(AQ_LOG_ERROR, std::format("Output {} failed: no surface given. Errno: {}", name, errno));
return; return;
} }
waylandState.xdgSurface = makeShared<CXdgSurface>(backend->waylandState.xdg->sendGetXdgSurface(waylandState.surface->resource())); waylandState.xdgSurface = makeShared<CCXdgSurface>(backend->waylandState.xdg->sendGetXdgSurface(waylandState.surface->resource()));
if (!waylandState.xdgSurface->resource()) { if (!waylandState.xdgSurface->resource()) {
backend->backend->log(AQ_LOG_ERROR, std::format("Output {} failed: no xdgSurface given. Errno: {}", name, errno)); backend->backend->log(AQ_LOG_ERROR, std::format("Output {} failed: no xdgSurface given. Errno: {}", name, errno));
return; return;
} }
waylandState.xdgSurface->setConfigure([this](CXdgSurface* r, uint32_t serial) { waylandState.xdgSurface->setConfigure([this](CCXdgSurface* r, uint32_t serial) {
backend->backend->log(AQ_LOG_DEBUG, std::format("Output {}: configure surface with {}", name, serial)); backend->backend->log(AQ_LOG_DEBUG, std::format("Output {}: configure surface with {}", name, serial));
r->sendAckConfigure(serial); r->sendAckConfigure(serial);
}); });
waylandState.xdgToplevel = makeShared<CXdgToplevel>(waylandState.xdgSurface->sendGetToplevel()); waylandState.xdgToplevel = makeShared<CCXdgToplevel>(waylandState.xdgSurface->sendGetToplevel());
if (!waylandState.xdgToplevel->resource()) { if (!waylandState.xdgToplevel->resource()) {
backend->backend->log(AQ_LOG_ERROR, std::format("Output {} failed: no xdgToplevel given. Errno: {}", name, errno)); backend->backend->log(AQ_LOG_ERROR, std::format("Output {} failed: no xdgToplevel given. Errno: {}", name, errno));
@ -326,24 +352,15 @@ Aquamarine::CWaylandOutput::CWaylandOutput(const std::string& name_, Hyprutils::
} }
waylandState.xdgToplevel->setWmCapabilities( waylandState.xdgToplevel->setWmCapabilities(
[this](CXdgToplevel* r, wl_array* arr) { backend->backend->log(AQ_LOG_DEBUG, std::format("Output {}: wm_capabilities received", name)); }); [this](CCXdgToplevel* r, wl_array* arr) { backend->backend->log(AQ_LOG_DEBUG, std::format("Output {}: wm_capabilities received", name)); });
waylandState.xdgToplevel->setConfigure([this](CXdgToplevel* r, int32_t w, int32_t h, wl_array* arr) {
// we only create the swapchain here because in the main func we still don't have an allocator
if (!swapchain) {
swapchain = makeShared<CSwapchain>(backend->backend->allocator);
if (!swapchain) {
backend->backend->log(AQ_LOG_ERROR, std::format("Output {} failed: swapchain creation failed", name));
return;
}
}
waylandState.xdgToplevel->setConfigure([this](CCXdgToplevel* r, int32_t w, int32_t h, wl_array* arr) {
backend->backend->log(AQ_LOG_DEBUG, std::format("Output {}: configure toplevel with {}x{}", name, w, h)); backend->backend->log(AQ_LOG_DEBUG, std::format("Output {}: configure toplevel with {}x{}", name, w, h));
events.state.emit(SStateEvent{.size = {w, h}}); events.state.emit(SStateEvent{.size = {w, h}});
sendFrameAndSetCallback(); sendFrameAndSetCallback();
}); });
auto inputRegion = makeShared<CWlRegion>(backend->waylandState.compositor->sendCreateRegion()); auto inputRegion = makeShared<CCWlRegion>(backend->waylandState.compositor->sendCreateRegion());
inputRegion->sendAdd(0, 0, INT32_MAX, INT32_MAX); inputRegion->sendAdd(0, 0, INT32_MAX, INT32_MAX);
waylandState.surface->sendSetInputRegion(inputRegion.get()); waylandState.surface->sendSetInputRegion(inputRegion.get());
@ -364,6 +381,10 @@ Aquamarine::CWaylandOutput::~CWaylandOutput() {
waylandState.surface->sendDestroy(); waylandState.surface->sendDestroy();
} }
bool Aquamarine::CWaylandOutput::test() {
return true; // TODO:
}
bool Aquamarine::CWaylandOutput::commit() { bool Aquamarine::CWaylandOutput::commit() {
Vector2D pixelSize = {}; Vector2D pixelSize = {};
uint32_t refreshRate = 0; uint32_t refreshRate = 0;
@ -384,6 +405,11 @@ bool Aquamarine::CWaylandOutput::commit() {
return false; return false;
} }
if (!swapchain) {
backend->backend->log(AQ_LOG_ERROR, std::format("Output {}: no swapchain, lying because it will soon be here", name));
return true;
}
if (!swapchain->reconfigure(SSwapchainOptions{.length = 2, .size = pixelSize, .format = format})) { if (!swapchain->reconfigure(SSwapchainOptions{.length = 2, .size = pixelSize, .format = format})) {
backend->backend->log(AQ_LOG_ERROR, std::format("Output {}: pending state rejected: swapchain failed reconfiguring", name)); backend->backend->log(AQ_LOG_ERROR, std::format("Output {}: pending state rejected: swapchain failed reconfiguring", name));
return false; return false;
@ -413,6 +439,10 @@ bool Aquamarine::CWaylandOutput::commit() {
return true; return true;
} }
SP<IBackendImplementation> Aquamarine::CWaylandOutput::getBackend() {
return SP<IBackendImplementation>(backend.lock());
}
SP<CWaylandBuffer> Aquamarine::CWaylandOutput::wlBufferFromBuffer(SP<IBuffer> buffer) { SP<CWaylandBuffer> Aquamarine::CWaylandOutput::wlBufferFromBuffer(SP<IBuffer> buffer) {
std::erase_if(backendState.buffers, [this](const auto& el) { return el.first.expired() || !swapchain->contains(el.first.lock()); }); std::erase_if(backendState.buffers, [this](const auto& el) { return el.first.expired() || !swapchain->contains(el.first.lock()); });
@ -439,15 +469,30 @@ void Aquamarine::CWaylandOutput::sendFrameAndSetCallback() {
if (waylandState.frameCallback) if (waylandState.frameCallback)
return; return;
waylandState.frameCallback = makeShared<CWlCallback>(waylandState.surface->sendFrame()); waylandState.frameCallback = makeShared<CCWlCallback>(waylandState.surface->sendFrame());
waylandState.frameCallback->setDone([this](CWlCallback* r, uint32_t ms) { waylandState.frameCallback->setDone([this](CCWlCallback* r, uint32_t ms) {
events.frame.emit(); events.frame.emit();
waylandState.frameCallback.reset(); waylandState.frameCallback.reset();
}); });
} }
bool Aquamarine::CWaylandOutput::setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot) {
return true;
}
void Aquamarine::CWaylandOutput::moveCursor(const Hyprutils::Math::Vector2D& coord) {
return;
}
void Aquamarine::CWaylandOutput::scheduleFrame() {
if (std::find(backend->scheduledFrames.begin(), backend->scheduledFrames.end(), self.lock()) != backend->scheduledFrames.end())
return;
backend->scheduledFrames.emplace_back(self.lock());
}
Aquamarine::CWaylandBuffer::CWaylandBuffer(SP<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_) : buffer(buffer_), backend(backend_) { Aquamarine::CWaylandBuffer::CWaylandBuffer(SP<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CWaylandBackend> backend_) : buffer(buffer_), backend(backend_) {
auto params = makeShared<CZwpLinuxBufferParamsV1>(backend->waylandState.dmabuf->sendCreateParams()); auto params = makeShared<CCZwpLinuxBufferParamsV1>(backend->waylandState.dmabuf->sendCreateParams());
if (!params) { if (!params) {
backend->backend->log(AQ_LOG_ERROR, "WaylandBuffer: failed to query params"); backend->backend->log(AQ_LOG_ERROR, "WaylandBuffer: failed to query params");
@ -460,9 +505,9 @@ Aquamarine::CWaylandBuffer::CWaylandBuffer(SP<IBuffer> buffer_, Hyprutils::Memor
params->sendAdd(attrs.fds.at(i), i, attrs.offsets.at(i), attrs.strides.at(i), attrs.modifier >> 32, attrs.modifier & 0xFFFFFFFF); params->sendAdd(attrs.fds.at(i), i, attrs.offsets.at(i), attrs.strides.at(i), attrs.modifier >> 32, attrs.modifier & 0xFFFFFFFF);
} }
waylandState.buffer = makeShared<CWlBuffer>(params->sendCreateImmed(attrs.size.x, attrs.size.y, attrs.format, (zwpLinuxBufferParamsV1Flags)0)); waylandState.buffer = makeShared<CCWlBuffer>(params->sendCreateImmed(attrs.size.x, attrs.size.y, attrs.format, (zwpLinuxBufferParamsV1Flags)0));
waylandState.buffer->setRelease([this](CWlBuffer* r) { pendingRelease = false; }); waylandState.buffer->setRelease([this](CCWlBuffer* r) { pendingRelease = false; });
params->sendDestroy(); params->sendDestroy();
} }

24
src/output/Output.cpp Normal file
View file

@ -0,0 +1,24 @@
#include <aquamarine/output/Output.hpp>
using namespace Aquamarine;
Hyprutils::Memory::CSharedPointer<SOutputMode> Aquamarine::IOutput::preferredMode() {
for (auto& m : modes) {
if (m->preferred)
return m;
}
return nullptr;
}
void Aquamarine::IOutput::moveCursor(const Hyprutils::Math::Vector2D& coord) {
;
}
bool Aquamarine::IOutput::setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot) {
return false;
}
void Aquamarine::IOutput::scheduleFrame() {
;
}

View file

@ -2,6 +2,7 @@
#include <aquamarine/output/Output.hpp> #include <aquamarine/output/Output.hpp>
#include <aquamarine/input/Input.hpp> #include <aquamarine/input/Input.hpp>
#include <iostream> #include <iostream>
#include <wayland-server.h>
using namespace Hyprutils::Signal; using namespace Hyprutils::Signal;
using namespace Hyprutils::Memory; using namespace Hyprutils::Memory;
@ -41,7 +42,7 @@ void onState(const Aquamarine::IOutput::SStateEvent& event) {
std::cout << "[Client] onState with size " << std::format("{}", event.size) << "\n"; std::cout << "[Client] onState with size " << std::format("{}", event.size) << "\n";
output->state->enabled = true; output->state->enabled = true;
output->state->customMode = {.pixelSize = event.size}; output->state->customMode = makeShared<Aquamarine::SOutputMode>(Aquamarine::SOutputMode{.pixelSize = event.size});
output->state->drmFormat = DRM_FORMAT_XRGB8888; output->state->drmFormat = DRM_FORMAT_XRGB8888;
output->commit(); output->commit();