mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-22 07:01:30 +00:00
[client] displayserver: support external event sources
Allow display servers to dispatch a caller-owned event source on their native event thread. This lets background input readers marshal events to the thread that owns application and display-server state. Poll X11 fairly when native events remain continuously available, and use bounded polling if the external descriptor cannot be registered.
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <wayland-client.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
@@ -105,6 +106,14 @@ static bool getCompositor(char * dst, size_t size)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void eventSourceCallback(uint32_t events, void * opaque)
|
||||
{
|
||||
(void)events;
|
||||
|
||||
const LG_DSEventSource * source = (const LG_DSEventSource *)opaque;
|
||||
source->callback(source->opaque);
|
||||
}
|
||||
|
||||
static bool waylandInit(const LG_DSInitParams params)
|
||||
{
|
||||
memset(&wlWm, 0, sizeof(wlWm));
|
||||
@@ -121,6 +130,7 @@ static bool waylandInit(const LG_DSInitParams params)
|
||||
atomic_init(&wlWm.hdrScRGBWhiteLevel, 80);
|
||||
atomic_init(&wlWm.pendingResize, 0);
|
||||
wlWm.resizeEventFd = -1;
|
||||
wlWm.eventSource = params.eventSource;
|
||||
|
||||
wlWm.display = wl_display_connect(NULL);
|
||||
if (!wlWm.display)
|
||||
@@ -152,6 +162,14 @@ static bool waylandInit(const LG_DSInitParams params)
|
||||
if (!waylandPollInit())
|
||||
return false;
|
||||
|
||||
if (wlWm.eventSource.fd >= 0 && wlWm.eventSource.callback &&
|
||||
!waylandPollRegister(wlWm.eventSource.fd, eventSourceCallback,
|
||||
&wlWm.eventSource, EPOLLIN))
|
||||
{
|
||||
DEBUG_ERROR("Failed to register the external event source");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!waylandOutputInit())
|
||||
return false;
|
||||
|
||||
|
||||
@@ -283,6 +283,7 @@ struct WaylandDSState
|
||||
unsigned int pollWaiters;
|
||||
int epollFd;
|
||||
int displayFd;
|
||||
LG_DSEventSource eventSource;
|
||||
};
|
||||
|
||||
struct WCBTransfer
|
||||
|
||||
@@ -443,6 +443,7 @@ static bool x11Init(const LG_DSInitParams params)
|
||||
x11InputInit(&x11.input, &inputSink, NULL);
|
||||
LG_LOCK_INIT(x11.pointerLock);
|
||||
atomic_init(&x11.captureActive, false);
|
||||
x11.eventSource = params.eventSource;
|
||||
x11.xValuator = -1;
|
||||
x11.yValuator = -1;
|
||||
x11.numLockIndicator = -1;
|
||||
@@ -1063,6 +1064,12 @@ static bool x11GetProp(LG_DSProperty prop, void *ret)
|
||||
|
||||
static int x11EventThread(void * unused)
|
||||
{
|
||||
enum
|
||||
{
|
||||
EPOLL_SOURCE_X11,
|
||||
EPOLL_SOURCE_EXTERNAL,
|
||||
};
|
||||
|
||||
int epollfd = epoll_create1(0);
|
||||
if (epollfd == -1)
|
||||
{
|
||||
@@ -1070,7 +1077,11 @@ static int x11EventThread(void * unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct epoll_event ev = { .events = EPOLLIN };
|
||||
struct epoll_event ev =
|
||||
{
|
||||
.events = EPOLLIN,
|
||||
.data.u32 = EPOLL_SOURCE_X11,
|
||||
};
|
||||
const int fd = ConnectionNumber(x11.display);
|
||||
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1)
|
||||
{
|
||||
@@ -1079,6 +1090,18 @@ static int x11EventThread(void * unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool pollEventSource = false;
|
||||
if (x11.eventSource.fd >= 0 && x11.eventSource.callback)
|
||||
{
|
||||
ev.data.u32 = EPOLL_SOURCE_EXTERNAL;
|
||||
if (epoll_ctl(epollfd, EPOLL_CTL_ADD,
|
||||
x11.eventSource.fd, &ev) == -1)
|
||||
{
|
||||
DEBUG_WARN("Failed to register the external event source; polling");
|
||||
pollEventSource = true;
|
||||
}
|
||||
}
|
||||
|
||||
while(app_isRunning())
|
||||
{
|
||||
const uint64_t lastWMEvent = atomic_load(&x11.lastWMEvent);
|
||||
@@ -1088,10 +1111,10 @@ static int x11EventThread(void * unused)
|
||||
app_invalidateWindow(true);
|
||||
}
|
||||
|
||||
if (!XPending(x11.display))
|
||||
{
|
||||
struct epoll_event events[1];
|
||||
int nfds = epoll_wait(epollfd, events, 1, 100);
|
||||
const bool xPending = XPending(x11.display) != 0;
|
||||
struct epoll_event events[2];
|
||||
const int nfds = epoll_wait(epollfd, events, ARRAY_LENGTH(events),
|
||||
xPending ? 0 : pollEventSource ? 10 : 100);
|
||||
if (nfds == -1)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
@@ -1102,9 +1125,15 @@ static int x11EventThread(void * unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nfds == 0 || !XPending(x11.display))
|
||||
for (int i = 0; i < nfds; ++i)
|
||||
if (events[i].data.u32 == EPOLL_SOURCE_EXTERNAL)
|
||||
x11.eventSource.callback(x11.eventSource.opaque);
|
||||
|
||||
if (pollEventSource)
|
||||
x11.eventSource.callback(x11.eventSource.opaque);
|
||||
|
||||
if (!XPending(x11.display))
|
||||
continue;
|
||||
}
|
||||
|
||||
XEvent xe;
|
||||
XNextEvent(x11.display, &xe);
|
||||
|
||||
@@ -102,6 +102,7 @@ struct X11DSState
|
||||
int yValuator;
|
||||
|
||||
X11Input input;
|
||||
LG_DSEventSource eventSource;
|
||||
LG_Lock pointerLock;
|
||||
_Atomic(bool) captureActive;
|
||||
bool fullscreen;
|
||||
|
||||
@@ -103,6 +103,18 @@ LG_DSWaitFrameResult;
|
||||
|
||||
#define LG_POINTER_COUNT (LG_POINTER_NOT_ALLOWED + 1)
|
||||
|
||||
typedef void (*LG_DSEventCallback)(void * opaque);
|
||||
|
||||
typedef struct LG_DSEventSource
|
||||
{
|
||||
/* The callback must be nonblocking and tolerate spurious calls. The caller
|
||||
* retains ownership of fd and opaque until display-server shutdown. */
|
||||
int fd;
|
||||
LG_DSEventCallback callback;
|
||||
void * opaque;
|
||||
}
|
||||
LG_DSEventSource;
|
||||
|
||||
typedef struct LG_DSInitParams
|
||||
{
|
||||
const char * title;
|
||||
@@ -122,6 +134,8 @@ typedef struct LG_DSInitParams
|
||||
// x11 needs to know if this is in use so we can decide to setup for
|
||||
// presentation times
|
||||
bool jitRender;
|
||||
|
||||
LG_DSEventSource eventSource;
|
||||
}
|
||||
LG_DSInitParams;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user