mirror of
https://github.com/hyprwm/aquamarine.git
synced 2024-12-22 10:29:48 +01:00
backend: rework event loop api
This commit is contained in:
parent
461d33583a
commit
511600133c
9 changed files with 77 additions and 137 deletions
|
@ -51,6 +51,11 @@ namespace Aquamarine {
|
||||||
std::function<void(eBackendLogLevel, std::string)> logFunction;
|
std::function<void(eBackendLogLevel, std::string)> logFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SPollFD {
|
||||||
|
int fd = -1;
|
||||||
|
std::function<void(void)> onSignal; /* call this when signaled */
|
||||||
|
};
|
||||||
|
|
||||||
class IBackendImplementation {
|
class IBackendImplementation {
|
||||||
public:
|
public:
|
||||||
virtual ~IBackendImplementation() {
|
virtual ~IBackendImplementation() {
|
||||||
|
@ -61,15 +66,15 @@ namespace Aquamarine {
|
||||||
AQ_BACKEND_CAPABILITY_POINTER = (1 << 0),
|
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 std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> pollFDs() = 0;
|
||||||
virtual int drmFD() = 0;
|
virtual int drmFD() = 0;
|
||||||
virtual bool dispatchEvents() = 0;
|
virtual bool dispatchEvents() = 0;
|
||||||
virtual uint32_t capabilities() = 0;
|
virtual uint32_t capabilities() = 0;
|
||||||
virtual void onReady() = 0;
|
virtual void onReady() = 0;
|
||||||
virtual std::vector<SDRMFormat> getRenderFormats() = 0;
|
virtual std::vector<SDRMFormat> getRenderFormats() = 0;
|
||||||
virtual std::vector<SDRMFormat> getCursorFormats() = 0;
|
virtual std::vector<SDRMFormat> getCursorFormats() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CBackend {
|
class CBackend {
|
||||||
|
@ -84,15 +89,8 @@ 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,
|
/* Gets all the FDs you have to poll. When any single one fires, call its onPoll */
|
||||||
see the async methods further below */
|
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> getPollFDs();
|
||||||
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 */
|
/* Checks if the backend has a session - iow if it's a DRM backend */
|
||||||
bool hasSession();
|
bool hasSession();
|
||||||
|
@ -126,7 +124,7 @@ namespace Aquamarine {
|
||||||
std::vector<Hyprutils::Memory::CSharedPointer<IBackendImplementation>> implementations;
|
std::vector<Hyprutils::Memory::CSharedPointer<IBackendImplementation>> implementations;
|
||||||
SBackendOptions options;
|
SBackendOptions options;
|
||||||
Hyprutils::Memory::CWeakPointer<CBackend> self;
|
Hyprutils::Memory::CWeakPointer<CBackend> self;
|
||||||
std::vector<int> sessionFDs;
|
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> sessionFDs;
|
||||||
|
|
||||||
//
|
//
|
||||||
struct {
|
struct {
|
||||||
|
|
|
@ -253,23 +253,23 @@ namespace Aquamarine {
|
||||||
class CDRMBackend : public IBackendImplementation {
|
class CDRMBackend : public IBackendImplementation {
|
||||||
public:
|
public:
|
||||||
virtual ~CDRMBackend();
|
virtual ~CDRMBackend();
|
||||||
virtual eBackendType type();
|
virtual eBackendType type();
|
||||||
virtual bool start();
|
virtual bool start();
|
||||||
virtual int pollFD();
|
virtual std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> pollFDs();
|
||||||
virtual int drmFD();
|
virtual int drmFD();
|
||||||
virtual bool dispatchEvents();
|
virtual bool dispatchEvents();
|
||||||
virtual uint32_t capabilities();
|
virtual uint32_t capabilities();
|
||||||
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
|
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
|
||||||
virtual void onReady();
|
virtual void onReady();
|
||||||
virtual std::vector<SDRMFormat> getRenderFormats();
|
virtual std::vector<SDRMFormat> getRenderFormats();
|
||||||
virtual std::vector<SDRMFormat> getCursorFormats();
|
virtual std::vector<SDRMFormat> getCursorFormats();
|
||||||
|
|
||||||
Hyprutils::Memory::CWeakPointer<CDRMBackend> self;
|
Hyprutils::Memory::CWeakPointer<CDRMBackend> self;
|
||||||
|
|
||||||
void log(eBackendLogLevel, const std::string&);
|
void log(eBackendLogLevel, const std::string&);
|
||||||
bool sessionActive();
|
bool sessionActive();
|
||||||
|
|
||||||
std::vector<FIdleCallback> idleCallbacks;
|
std::vector<FIdleCallback> idleCallbacks;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CDRMBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend);
|
CDRMBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend);
|
||||||
|
|
|
@ -18,6 +18,7 @@ namespace Aquamarine {
|
||||||
class CBackend;
|
class CBackend;
|
||||||
class CSession;
|
class CSession;
|
||||||
class CLibinputDevice;
|
class CLibinputDevice;
|
||||||
|
struct SPollFD;
|
||||||
|
|
||||||
class CSessionDevice {
|
class CSessionDevice {
|
||||||
public:
|
public:
|
||||||
|
@ -118,7 +119,7 @@ namespace Aquamarine {
|
||||||
libseat* libseatHandle = nullptr;
|
libseat* libseatHandle = nullptr;
|
||||||
libinput* libinputHandle = nullptr;
|
libinput* libinputHandle = nullptr;
|
||||||
|
|
||||||
std::vector<int> pollFDs();
|
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> pollFDs();
|
||||||
void dispatchPendingEventsAsync();
|
void dispatchPendingEventsAsync();
|
||||||
bool switchVT(uint32_t vt);
|
bool switchVT(uint32_t vt);
|
||||||
void onReady();
|
void onReady();
|
||||||
|
@ -134,11 +135,13 @@ namespace Aquamarine {
|
||||||
} events;
|
} events;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Hyprutils::Memory::CWeakPointer<CBackend> backend;
|
Hyprutils::Memory::CWeakPointer<CBackend> backend;
|
||||||
|
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> polls;
|
||||||
|
|
||||||
void dispatchUdevEvents();
|
void dispatchUdevEvents();
|
||||||
void dispatchLibinputEvents();
|
void dispatchLibinputEvents();
|
||||||
void handleLibinputEvent(libinput_event* e);
|
void dispatchLibseatEvents();
|
||||||
|
void handleLibinputEvent(libinput_event* e);
|
||||||
|
|
||||||
friend class CSessionDevice;
|
friend class CSessionDevice;
|
||||||
friend class CLibinputDevice;
|
friend class CLibinputDevice;
|
||||||
|
|
|
@ -121,18 +121,18 @@ namespace Aquamarine {
|
||||||
class CWaylandBackend : public IBackendImplementation {
|
class CWaylandBackend : public IBackendImplementation {
|
||||||
public:
|
public:
|
||||||
virtual ~CWaylandBackend();
|
virtual ~CWaylandBackend();
|
||||||
virtual eBackendType type();
|
virtual eBackendType type();
|
||||||
virtual bool start();
|
virtual bool start();
|
||||||
virtual int pollFD();
|
virtual std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> pollFDs();
|
||||||
virtual int drmFD();
|
virtual int drmFD();
|
||||||
virtual bool dispatchEvents();
|
virtual bool dispatchEvents();
|
||||||
virtual uint32_t capabilities();
|
virtual uint32_t capabilities();
|
||||||
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
|
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
|
||||||
virtual void onReady();
|
virtual void onReady();
|
||||||
virtual std::vector<SDRMFormat> getRenderFormats();
|
virtual std::vector<SDRMFormat> getRenderFormats();
|
||||||
virtual std::vector<SDRMFormat> getCursorFormats();
|
virtual std::vector<SDRMFormat> getCursorFormats();
|
||||||
|
|
||||||
Hyprutils::Memory::CWeakPointer<CWaylandBackend> self;
|
Hyprutils::Memory::CWeakPointer<CWaylandBackend> self;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CWaylandBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend);
|
CWaylandBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend);
|
||||||
|
|
|
@ -100,7 +100,7 @@ bool Aquamarine::CBackend::start() {
|
||||||
|
|
||||||
// erase failed impls
|
// erase failed impls
|
||||||
std::erase_if(implementations, [this](const auto& i) {
|
std::erase_if(implementations, [this](const auto& i) {
|
||||||
bool failed = i->pollFD() < 0;
|
bool failed = i->pollFDs().empty();
|
||||||
if (failed)
|
if (failed)
|
||||||
log(AQ_LOG_ERROR, std::format("Implementation {} failed, erasing.", backendTypeToName(i->type())));
|
log(AQ_LOG_ERROR, std::format("Implementation {} failed, erasing.", backendTypeToName(i->type())));
|
||||||
return failed;
|
return failed;
|
||||||
|
@ -122,7 +122,7 @@ bool Aquamarine::CBackend::start() {
|
||||||
b->onReady();
|
b->onReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionFDs = session ? session->pollFDs() : std::vector<int>{};
|
sessionFDs = session ? session->pollFDs() : std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>>{};
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -134,76 +134,17 @@ void Aquamarine::CBackend::log(eBackendLogLevel level, const std::string& msg) {
|
||||||
options.logFunction(level, msg);
|
options.logFunction(level, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Aquamarine::CBackend::enterLoop() {
|
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> Aquamarine::CBackend::getPollFDs() {
|
||||||
std::vector<pollfd> pollFDs;
|
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> result;
|
||||||
|
|
||||||
for (auto& i : implementations) {
|
for (auto& i : implementations) {
|
||||||
auto fd = i->pollFD();
|
auto pollfds = i->pollFDs();
|
||||||
|
for (auto& p : pollfds) {
|
||||||
pollFDs.emplace_back(pollfd{.fd = fd, .events = POLLIN, .revents = 0});
|
result.emplace_back(p);
|
||||||
}
|
|
||||||
|
|
||||||
std::thread pollThr([this, &pollFDs]() {
|
|
||||||
int ret = 0;
|
|
||||||
while (1) {
|
|
||||||
ret = poll(pollFDs.data(), pollFDs.size(), 5000 /* 5 seconds, reasonable. It's because we might need to terminate */);
|
|
||||||
if (ret < 0) {
|
|
||||||
log(AQ_LOG_CRITICAL, std::format("Polling fds failed with {}", errno));
|
|
||||||
terminate = true;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < pollFDs.size(); ++i) {
|
|
||||||
if (pollFDs[i].revents & POLLHUP) {
|
|
||||||
log(AQ_LOG_CRITICAL, std::format("disconnected from pollfd {}", i));
|
|
||||||
terminate = true;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (terminate)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (ret != 0) {
|
|
||||||
std::lock_guard<std::mutex> lg(m_sEventLoopInternals.loopRequestMutex);
|
|
||||||
m_sEventLoopInternals.shouldProcess = true;
|
|
||||||
m_sEventLoopInternals.loopSignal.notify_all();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
m_sEventLoopInternals.loopRequestMutex.unlock(); // unlock, we are ready to take events
|
|
||||||
|
|
||||||
std::unique_lock lk(m_sEventLoopInternals.loopMutex);
|
|
||||||
if (m_sEventLoopInternals.shouldProcess == false) // avoid a lock if a thread managed to request something already since we .unlock()ed
|
|
||||||
m_sEventLoopInternals.loopSignal.wait_for(lk, std::chrono::seconds(5), [this] { return m_sEventLoopInternals.shouldProcess == true; }); // wait for events
|
|
||||||
|
|
||||||
m_sEventLoopInternals.loopRequestMutex.lock(); // lock incoming events
|
|
||||||
|
|
||||||
if (terminate)
|
|
||||||
break;
|
|
||||||
|
|
||||||
m_sEventLoopInternals.shouldProcess = false;
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lg(m_sEventLoopInternals.eventLock);
|
|
||||||
|
|
||||||
dispatchEventsAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& sfd : sessionFDs) {
|
for (auto& sfd : sessionFDs) {
|
||||||
result.push_back(sfd);
|
result.emplace_back(sfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -220,15 +161,6 @@ int Aquamarine::CBackend::drmFD() {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Aquamarine::CBackend::dispatchEventsAsync() {
|
|
||||||
for (auto& i : implementations) {
|
|
||||||
i->dispatchEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (session)
|
|
||||||
session->dispatchPendingEventsAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Aquamarine::CBackend::hasSession() {
|
bool Aquamarine::CBackend::hasSession() {
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
|
@ -353,19 +353,25 @@ void Aquamarine::CSession::dispatchLibinputEvents() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Aquamarine::CSession::dispatchPendingEventsAsync() {
|
void Aquamarine::CSession::dispatchLibseatEvents() {
|
||||||
if (libseat_dispatch(libseatHandle, 0) == -1)
|
if (libseat_dispatch(libseatHandle, 0) == -1)
|
||||||
backend->log(AQ_LOG_ERROR, "Couldn't dispatch libseat events");
|
backend->log(AQ_LOG_ERROR, "Couldn't dispatch libseat events");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Aquamarine::CSession::dispatchPendingEventsAsync() {
|
||||||
|
dispatchLibseatEvents();
|
||||||
dispatchUdevEvents();
|
dispatchUdevEvents();
|
||||||
dispatchLibinputEvents();
|
dispatchLibinputEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> Aquamarine::CSession::pollFDs() {
|
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> Aquamarine::CSession::pollFDs() {
|
||||||
if (!libseatHandle || !udevMonitor || !udevHandle)
|
// clang-format off
|
||||||
return {};
|
return {
|
||||||
|
makeShared<SPollFD>(libseat_get_fd(libseatHandle), [this](){ dispatchLibseatEvents(); }),
|
||||||
return {libseat_get_fd(libseatHandle), udev_monitor_get_fd(udevMonitor), libinput_get_fd(libinputHandle)};
|
makeShared<SPollFD>(udev_monitor_get_fd(udevMonitor), [this](){ dispatchUdevEvents(); }),
|
||||||
|
makeShared<SPollFD>(libinput_get_fd(libinputHandle), [this](){ dispatchLibinputEvents(); })
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Aquamarine::CSession::switchVT(uint32_t vt) {
|
bool Aquamarine::CSession::switchVT(uint32_t vt) {
|
||||||
|
|
|
@ -140,11 +140,11 @@ void Aquamarine::CWaylandBackend::createOutput(const std::string& szName) {
|
||||||
idleCallbacks.emplace_back([this, o]() { backend->events.newOutput.emit(SP<IOutput>(o)); });
|
idleCallbacks.emplace_back([this, o]() { backend->events.newOutput.emit(SP<IOutput>(o)); });
|
||||||
}
|
}
|
||||||
|
|
||||||
int Aquamarine::CWaylandBackend::pollFD() {
|
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> Aquamarine::CWaylandBackend::pollFDs() {
|
||||||
if (!waylandState.display)
|
if (!waylandState.display)
|
||||||
return -1;
|
return {};
|
||||||
|
|
||||||
return wl_display_get_fd(waylandState.display);
|
return {makeShared<SPollFD>(wl_display_get_fd(waylandState.display), [this]() { dispatchEvents(); })};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Aquamarine::CWaylandBackend::dispatchEvents() {
|
bool Aquamarine::CWaylandBackend::dispatchEvents() {
|
||||||
|
|
|
@ -476,8 +476,8 @@ bool Aquamarine::CDRMBackend::start() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Aquamarine::CDRMBackend::pollFD() {
|
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> Aquamarine::CDRMBackend::pollFDs() {
|
||||||
return gpu->fd;
|
return {makeShared<SPollFD>(gpu->fd, [this]() { dispatchEvents(); })};
|
||||||
}
|
}
|
||||||
|
|
||||||
int Aquamarine::CDRMBackend::drmFD() {
|
int Aquamarine::CDRMBackend::drmFD() {
|
||||||
|
|
|
@ -90,7 +90,8 @@ int main(int argc, char** argv, char** envp) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
aqBackend->enterLoop();
|
// FIXME: write an event loop.
|
||||||
|
// aqBackend->enterLoop();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
Loading…
Reference in a new issue