mirror of
https://github.com/hyprwm/aquamarine.git
synced 2024-11-17 01:25:59 +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;
|
||||
};
|
||||
|
||||
struct SPollFD {
|
||||
int fd = -1;
|
||||
std::function<void(void)> onSignal; /* call this when signaled */
|
||||
};
|
||||
|
||||
class IBackendImplementation {
|
||||
public:
|
||||
virtual ~IBackendImplementation() {
|
||||
|
@ -61,15 +66,15 @@ namespace Aquamarine {
|
|||
AQ_BACKEND_CAPABILITY_POINTER = (1 << 0),
|
||||
};
|
||||
|
||||
virtual eBackendType type() = 0;
|
||||
virtual bool start() = 0;
|
||||
virtual int pollFD() = 0;
|
||||
virtual int drmFD() = 0;
|
||||
virtual bool dispatchEvents() = 0;
|
||||
virtual uint32_t capabilities() = 0;
|
||||
virtual void onReady() = 0;
|
||||
virtual std::vector<SDRMFormat> getRenderFormats() = 0;
|
||||
virtual std::vector<SDRMFormat> getCursorFormats() = 0;
|
||||
virtual eBackendType type() = 0;
|
||||
virtual bool start() = 0;
|
||||
virtual std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> pollFDs() = 0;
|
||||
virtual int drmFD() = 0;
|
||||
virtual bool dispatchEvents() = 0;
|
||||
virtual uint32_t capabilities() = 0;
|
||||
virtual void onReady() = 0;
|
||||
virtual std::vector<SDRMFormat> getRenderFormats() = 0;
|
||||
virtual std::vector<SDRMFormat> getCursorFormats() = 0;
|
||||
};
|
||||
|
||||
class CBackend {
|
||||
|
@ -84,15 +89,8 @@ namespace Aquamarine {
|
|||
|
||||
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,
|
||||
see the async methods further below */
|
||||
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();
|
||||
/* Gets all the FDs you have to poll. When any single one fires, call its onPoll */
|
||||
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> getPollFDs();
|
||||
|
||||
/* Checks if the backend has a session - iow if it's a DRM backend */
|
||||
bool hasSession();
|
||||
|
@ -126,7 +124,7 @@ namespace Aquamarine {
|
|||
std::vector<Hyprutils::Memory::CSharedPointer<IBackendImplementation>> implementations;
|
||||
SBackendOptions options;
|
||||
Hyprutils::Memory::CWeakPointer<CBackend> self;
|
||||
std::vector<int> sessionFDs;
|
||||
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> sessionFDs;
|
||||
|
||||
//
|
||||
struct {
|
||||
|
|
|
@ -253,23 +253,23 @@ namespace Aquamarine {
|
|||
class CDRMBackend : public IBackendImplementation {
|
||||
public:
|
||||
virtual ~CDRMBackend();
|
||||
virtual eBackendType type();
|
||||
virtual bool start();
|
||||
virtual int pollFD();
|
||||
virtual int drmFD();
|
||||
virtual bool dispatchEvents();
|
||||
virtual uint32_t capabilities();
|
||||
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
|
||||
virtual void onReady();
|
||||
virtual std::vector<SDRMFormat> getRenderFormats();
|
||||
virtual std::vector<SDRMFormat> getCursorFormats();
|
||||
virtual eBackendType type();
|
||||
virtual bool start();
|
||||
virtual std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> pollFDs();
|
||||
virtual int drmFD();
|
||||
virtual bool dispatchEvents();
|
||||
virtual uint32_t capabilities();
|
||||
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
|
||||
virtual void onReady();
|
||||
virtual std::vector<SDRMFormat> getRenderFormats();
|
||||
virtual std::vector<SDRMFormat> getCursorFormats();
|
||||
|
||||
Hyprutils::Memory::CWeakPointer<CDRMBackend> self;
|
||||
Hyprutils::Memory::CWeakPointer<CDRMBackend> self;
|
||||
|
||||
void log(eBackendLogLevel, const std::string&);
|
||||
bool sessionActive();
|
||||
void log(eBackendLogLevel, const std::string&);
|
||||
bool sessionActive();
|
||||
|
||||
std::vector<FIdleCallback> idleCallbacks;
|
||||
std::vector<FIdleCallback> idleCallbacks;
|
||||
|
||||
private:
|
||||
CDRMBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend);
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace Aquamarine {
|
|||
class CBackend;
|
||||
class CSession;
|
||||
class CLibinputDevice;
|
||||
struct SPollFD;
|
||||
|
||||
class CSessionDevice {
|
||||
public:
|
||||
|
@ -118,7 +119,7 @@ namespace Aquamarine {
|
|||
libseat* libseatHandle = nullptr;
|
||||
libinput* libinputHandle = nullptr;
|
||||
|
||||
std::vector<int> pollFDs();
|
||||
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> pollFDs();
|
||||
void dispatchPendingEventsAsync();
|
||||
bool switchVT(uint32_t vt);
|
||||
void onReady();
|
||||
|
@ -134,11 +135,13 @@ namespace Aquamarine {
|
|||
} events;
|
||||
|
||||
private:
|
||||
Hyprutils::Memory::CWeakPointer<CBackend> backend;
|
||||
Hyprutils::Memory::CWeakPointer<CBackend> backend;
|
||||
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> polls;
|
||||
|
||||
void dispatchUdevEvents();
|
||||
void dispatchLibinputEvents();
|
||||
void handleLibinputEvent(libinput_event* e);
|
||||
void dispatchUdevEvents();
|
||||
void dispatchLibinputEvents();
|
||||
void dispatchLibseatEvents();
|
||||
void handleLibinputEvent(libinput_event* e);
|
||||
|
||||
friend class CSessionDevice;
|
||||
friend class CLibinputDevice;
|
||||
|
|
|
@ -121,18 +121,18 @@ namespace Aquamarine {
|
|||
class CWaylandBackend : public IBackendImplementation {
|
||||
public:
|
||||
virtual ~CWaylandBackend();
|
||||
virtual eBackendType type();
|
||||
virtual bool start();
|
||||
virtual int pollFD();
|
||||
virtual int drmFD();
|
||||
virtual bool dispatchEvents();
|
||||
virtual uint32_t capabilities();
|
||||
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
|
||||
virtual void onReady();
|
||||
virtual std::vector<SDRMFormat> getRenderFormats();
|
||||
virtual std::vector<SDRMFormat> getCursorFormats();
|
||||
virtual eBackendType type();
|
||||
virtual bool start();
|
||||
virtual std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> pollFDs();
|
||||
virtual int drmFD();
|
||||
virtual bool dispatchEvents();
|
||||
virtual uint32_t capabilities();
|
||||
virtual bool setCursor(Hyprutils::Memory::CSharedPointer<IBuffer> buffer, const Hyprutils::Math::Vector2D& hotspot);
|
||||
virtual void onReady();
|
||||
virtual std::vector<SDRMFormat> getRenderFormats();
|
||||
virtual std::vector<SDRMFormat> getCursorFormats();
|
||||
|
||||
Hyprutils::Memory::CWeakPointer<CWaylandBackend> self;
|
||||
Hyprutils::Memory::CWeakPointer<CWaylandBackend> self;
|
||||
|
||||
private:
|
||||
CWaylandBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend);
|
||||
|
|
|
@ -100,7 +100,7 @@ bool Aquamarine::CBackend::start() {
|
|||
|
||||
// erase failed impls
|
||||
std::erase_if(implementations, [this](const auto& i) {
|
||||
bool failed = i->pollFD() < 0;
|
||||
bool failed = i->pollFDs().empty();
|
||||
if (failed)
|
||||
log(AQ_LOG_ERROR, std::format("Implementation {} failed, erasing.", backendTypeToName(i->type())));
|
||||
return failed;
|
||||
|
@ -122,7 +122,7 @@ bool Aquamarine::CBackend::start() {
|
|||
b->onReady();
|
||||
}
|
||||
|
||||
sessionFDs = session ? session->pollFDs() : std::vector<int>{};
|
||||
sessionFDs = session ? session->pollFDs() : std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>>{};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -134,76 +134,17 @@ void Aquamarine::CBackend::log(eBackendLogLevel level, const std::string& msg) {
|
|||
options.logFunction(level, msg);
|
||||
}
|
||||
|
||||
void Aquamarine::CBackend::enterLoop() {
|
||||
std::vector<pollfd> pollFDs;
|
||||
|
||||
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> Aquamarine::CBackend::getPollFDs() {
|
||||
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> result;
|
||||
for (auto& i : implementations) {
|
||||
auto fd = i->pollFD();
|
||||
|
||||
pollFDs.emplace_back(pollfd{.fd = fd, .events = POLLIN, .revents = 0});
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
auto pollfds = i->pollFDs();
|
||||
for (auto& p : pollfds) {
|
||||
result.emplace_back(p);
|
||||
}
|
||||
});
|
||||
|
||||
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) {
|
||||
result.push_back(sfd);
|
||||
result.emplace_back(sfd);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -220,15 +161,6 @@ int Aquamarine::CBackend::drmFD() {
|
|||
return -1;
|
||||
}
|
||||
|
||||
void Aquamarine::CBackend::dispatchEventsAsync() {
|
||||
for (auto& i : implementations) {
|
||||
i->dispatchEvents();
|
||||
}
|
||||
|
||||
if (session)
|
||||
session->dispatchPendingEventsAsync();
|
||||
}
|
||||
|
||||
bool Aquamarine::CBackend::hasSession() {
|
||||
return session;
|
||||
}
|
||||
|
|
|
@ -353,19 +353,25 @@ void Aquamarine::CSession::dispatchLibinputEvents() {
|
|||
}
|
||||
}
|
||||
|
||||
void Aquamarine::CSession::dispatchPendingEventsAsync() {
|
||||
void Aquamarine::CSession::dispatchLibseatEvents() {
|
||||
if (libseat_dispatch(libseatHandle, 0) == -1)
|
||||
backend->log(AQ_LOG_ERROR, "Couldn't dispatch libseat events");
|
||||
}
|
||||
|
||||
void Aquamarine::CSession::dispatchPendingEventsAsync() {
|
||||
dispatchLibseatEvents();
|
||||
dispatchUdevEvents();
|
||||
dispatchLibinputEvents();
|
||||
}
|
||||
|
||||
std::vector<int> Aquamarine::CSession::pollFDs() {
|
||||
if (!libseatHandle || !udevMonitor || !udevHandle)
|
||||
return {};
|
||||
|
||||
return {libseat_get_fd(libseatHandle), udev_monitor_get_fd(udevMonitor), libinput_get_fd(libinputHandle)};
|
||||
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> Aquamarine::CSession::pollFDs() {
|
||||
// clang-format off
|
||||
return {
|
||||
makeShared<SPollFD>(libseat_get_fd(libseatHandle), [this](){ dispatchLibseatEvents(); }),
|
||||
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) {
|
||||
|
|
|
@ -140,11 +140,11 @@ void Aquamarine::CWaylandBackend::createOutput(const std::string& szName) {
|
|||
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)
|
||||
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() {
|
||||
|
|
|
@ -476,8 +476,8 @@ bool Aquamarine::CDRMBackend::start() {
|
|||
return true;
|
||||
}
|
||||
|
||||
int Aquamarine::CDRMBackend::pollFD() {
|
||||
return gpu->fd;
|
||||
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> Aquamarine::CDRMBackend::pollFDs() {
|
||||
return {makeShared<SPollFD>(gpu->fd, [this]() { dispatchEvents(); })};
|
||||
}
|
||||
|
||||
int Aquamarine::CDRMBackend::drmFD() {
|
||||
|
|
|
@ -90,7 +90,8 @@ int main(int argc, char** argv, char** envp) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
aqBackend->enterLoop();
|
||||
// FIXME: write an event loop.
|
||||
// aqBackend->enterLoop();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue