replace qt event loop with epoll
This commit is contained in:
parent
dfae73b1c5
commit
31c09e24d6
1 changed files with 86 additions and 48 deletions
132
src/main.cpp
132
src/main.cpp
|
@ -5,6 +5,7 @@
|
|||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/stat.h>
|
||||
|
@ -14,10 +15,10 @@
|
|||
#include <list>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <QGuiApplication>
|
||||
#include <QSocketNotifier>
|
||||
#include <wayland-client.h>
|
||||
#include <wayland-cursor.h>
|
||||
#include <QGuiApplication>
|
||||
#include <QString>
|
||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
#include "net-tapesoftware-dwl-wm-unstable-v1-client-protocol.h"
|
||||
|
@ -44,10 +45,11 @@ struct Seat {
|
|||
};
|
||||
|
||||
static void waylandFlush();
|
||||
static void waylandWriteReady();
|
||||
static void requireGlobal(const void *p, const char *name);
|
||||
static void setupStatusFifo();
|
||||
static void onStatus();
|
||||
[[noreturn]] static void diesys(const char *why);
|
||||
[[noreturn]] static void die(const char *why);
|
||||
static void cleanup();
|
||||
|
||||
wl_display *display;
|
||||
|
@ -65,9 +67,10 @@ static std::list<Monitor> monitors;
|
|||
static std::list<Seat> seats;
|
||||
static QString lastStatus;
|
||||
static std::string statusFifoName;
|
||||
static int epoll {-1};
|
||||
static int displayFd {-1};
|
||||
static int statusFifoFd {-1};
|
||||
static int statusFifoWriter {-1};
|
||||
static QSocketNotifier *displayWriteNotifier;
|
||||
static bool quitting {false};
|
||||
|
||||
void view(Monitor &m, const Arg &arg)
|
||||
|
@ -245,28 +248,27 @@ static void setupStatusFifo()
|
|||
auto result = mkfifo(path.c_str(), 0666);
|
||||
if (result == 0) {
|
||||
auto fd = open(path.c_str(), O_CLOEXEC | O_NONBLOCK | O_RDONLY);
|
||||
if (fd == -1) {
|
||||
perror("open status fifo reader");
|
||||
cleanup();
|
||||
exit(1);
|
||||
if (fd < 0) {
|
||||
diesys("open status fifo reader");
|
||||
}
|
||||
statusFifoName = path;
|
||||
statusFifoFd = fd;
|
||||
|
||||
fd = open(path.c_str(), O_CLOEXEC | O_WRONLY);
|
||||
if (fd == -1) {
|
||||
perror("open status fifo writer");
|
||||
cleanup();
|
||||
exit(1);
|
||||
if (fd < 0) {
|
||||
diesys("open status fifo writer");
|
||||
}
|
||||
statusFifoWriter = fd;
|
||||
|
||||
auto statusNotifier = new QSocketNotifier(statusFifoFd, QSocketNotifier::Read);
|
||||
statusNotifier->setEnabled(true);
|
||||
QObject::connect(statusNotifier, &QSocketNotifier::activated, onStatus);
|
||||
epoll_event ev = {0};
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.fd = statusFifoFd;
|
||||
if (epoll_ctl(epoll, EPOLL_CTL_ADD, statusFifoFd, &ev) < 0) {
|
||||
diesys("epoll_ctl add status fifo");
|
||||
}
|
||||
return;
|
||||
} else if (errno != EEXIST) {
|
||||
perror("mkfifo");
|
||||
diesys("mkfifo");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -341,52 +343,87 @@ int main(int argc, char **argv)
|
|||
sigaddset(&blockedsigs, SIGTERM);
|
||||
sigprocmask(SIG_BLOCK, &blockedsigs, nullptr);
|
||||
|
||||
QGuiApplication app(argc, argv);
|
||||
QCoreApplication::setOrganizationName("tape software");
|
||||
QCoreApplication::setOrganizationDomain("tapesoftware.net");
|
||||
QCoreApplication::setApplicationName("somebar");
|
||||
QGuiApplication app {argc, argv};
|
||||
|
||||
epoll_event epollEv = {0};
|
||||
std::array<epoll_event, 5> epollEvents;
|
||||
epoll = epoll_create1(EPOLL_CLOEXEC);
|
||||
if (epoll < 0) {
|
||||
diesys("epoll_create1");
|
||||
}
|
||||
int sfd = signalfd(-1, &blockedsigs, SFD_CLOEXEC | SFD_NONBLOCK);
|
||||
if (sfd < 0) {
|
||||
perror("signalfd");
|
||||
cleanup();
|
||||
exit(1);
|
||||
diesys("signalfd");
|
||||
}
|
||||
epollEv.events = EPOLLIN;
|
||||
epollEv.data.fd = sfd;
|
||||
if (epoll_ctl(epoll, EPOLL_CTL_ADD, sfd, &epollEv) < 0) {
|
||||
diesys("epoll_ctl add signalfd");
|
||||
}
|
||||
QSocketNotifier signalNotifier {sfd, QSocketNotifier::Read};
|
||||
QObject::connect(&signalNotifier, &QSocketNotifier::activated, []() { quitting = true; });
|
||||
|
||||
display = wl_display_connect(NULL);
|
||||
display = wl_display_connect(nullptr);
|
||||
if (!display) {
|
||||
fprintf(stderr, "Failed to connect to Wayland display\n");
|
||||
return 1;
|
||||
die("Failed to connect to Wayland display");
|
||||
}
|
||||
displayFd = wl_display_get_fd(display);
|
||||
|
||||
auto registry = wl_display_get_registry(display);
|
||||
wl_registry_add_listener(registry, ®istry_listener, nullptr);
|
||||
wl_display_roundtrip(display);
|
||||
onReady();
|
||||
|
||||
QSocketNotifier displayReadNotifier(wl_display_get_fd(display), QSocketNotifier::Read);
|
||||
displayReadNotifier.setEnabled(true);
|
||||
QObject::connect(&displayReadNotifier, &QSocketNotifier::activated, [=]() {
|
||||
auto res = wl_display_dispatch(display);
|
||||
if (res < 0) {
|
||||
perror("wl_display_dispatch");
|
||||
cleanup();
|
||||
exit(1);
|
||||
epollEv.events = EPOLLIN;
|
||||
epollEv.data.fd = displayFd;
|
||||
if (epoll_ctl(epoll, EPOLL_CTL_ADD, displayFd, &epollEv) < 0) {
|
||||
diesys("epoll_ctl add wayland_display");
|
||||
}
|
||||
});
|
||||
displayWriteNotifier = new QSocketNotifier(wl_display_get_fd(display), QSocketNotifier::Write);
|
||||
displayWriteNotifier->setEnabled(false);
|
||||
QObject::connect(displayWriteNotifier, &QSocketNotifier::activated, waylandWriteReady);
|
||||
|
||||
while (!quitting) {
|
||||
waylandFlush();
|
||||
app.processEvents(QEventLoop::WaitForMoreEvents);
|
||||
auto res = epoll_wait(epoll, epollEvents.data(), epollEvents.size(), -1);
|
||||
if (res < 0) {
|
||||
if (errno != EINTR) {
|
||||
diesys("epoll_wait");
|
||||
}
|
||||
} else {
|
||||
for (auto i=0; i<res; i++) {
|
||||
auto &ev = epollEvents[i];
|
||||
if (ev.data.fd == displayFd) {
|
||||
if (ev.events & EPOLLIN) {
|
||||
if (wl_display_dispatch(display) < 0) {
|
||||
die("wl_display_dispatch");
|
||||
}
|
||||
} if (ev.events & EPOLLOUT) {
|
||||
epollEv.events = EPOLLIN;
|
||||
epollEv.data.fd = displayFd;
|
||||
if (epoll_ctl(epoll, EPOLL_CTL_MOD, displayFd, &epollEv) < 0) {
|
||||
diesys("epoll_ctl");
|
||||
}
|
||||
waylandFlush();
|
||||
}
|
||||
} else if (ev.data.fd == statusFifoFd) {
|
||||
onStatus();
|
||||
} else if (ev.data.fd == sfd) {
|
||||
quitting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void die(const char *why) {
|
||||
fprintf(stderr, "%s\n", why);
|
||||
cleanup();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void diesys(const char *why) {
|
||||
perror(why);
|
||||
cleanup();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
if (!statusFifoName.empty()) {
|
||||
unlink(statusFifoName.c_str());
|
||||
|
@ -397,14 +434,15 @@ void waylandFlush()
|
|||
{
|
||||
wl_display_dispatch_pending(display);
|
||||
if (wl_display_flush(display) < 0 && errno == EAGAIN) {
|
||||
displayWriteNotifier->setEnabled(true);
|
||||
epoll_event ev = {0};
|
||||
ev.events = EPOLLIN | EPOLLOUT;
|
||||
ev.data.fd = displayFd;
|
||||
if (epoll_ctl(epoll, EPOLL_CTL_MOD, displayFd, &ev) < 0) {
|
||||
diesys("epoll_ctl");
|
||||
}
|
||||
}
|
||||
}
|
||||
static void waylandWriteReady()
|
||||
{
|
||||
displayWriteNotifier->setEnabled(false);
|
||||
waylandFlush();
|
||||
}
|
||||
|
||||
static void requireGlobal(const void *p, const char *name)
|
||||
{
|
||||
if (p) return;
|
||||
|
|
Loading…
Reference in a new issue