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 <signal.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
@@ -105,6 +106,14 @@ static bool getCompositor(char * dst, size_t size)
|
|||||||
return true;
|
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)
|
static bool waylandInit(const LG_DSInitParams params)
|
||||||
{
|
{
|
||||||
memset(&wlWm, 0, sizeof(wlWm));
|
memset(&wlWm, 0, sizeof(wlWm));
|
||||||
@@ -121,6 +130,7 @@ static bool waylandInit(const LG_DSInitParams params)
|
|||||||
atomic_init(&wlWm.hdrScRGBWhiteLevel, 80);
|
atomic_init(&wlWm.hdrScRGBWhiteLevel, 80);
|
||||||
atomic_init(&wlWm.pendingResize, 0);
|
atomic_init(&wlWm.pendingResize, 0);
|
||||||
wlWm.resizeEventFd = -1;
|
wlWm.resizeEventFd = -1;
|
||||||
|
wlWm.eventSource = params.eventSource;
|
||||||
|
|
||||||
wlWm.display = wl_display_connect(NULL);
|
wlWm.display = wl_display_connect(NULL);
|
||||||
if (!wlWm.display)
|
if (!wlWm.display)
|
||||||
@@ -152,6 +162,14 @@ static bool waylandInit(const LG_DSInitParams params)
|
|||||||
if (!waylandPollInit())
|
if (!waylandPollInit())
|
||||||
return false;
|
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())
|
if (!waylandOutputInit())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|||||||
@@ -276,13 +276,14 @@ struct WaylandDSState
|
|||||||
_Atomic(unsigned) frameEventFlags;
|
_Atomic(unsigned) frameEventFlags;
|
||||||
LGEvent * frameEvent;
|
LGEvent * frameEvent;
|
||||||
|
|
||||||
struct wl_list poll; // WaylandPoll::link
|
struct wl_list poll; // WaylandPoll::link
|
||||||
struct wl_list pollFree; // WaylandPoll::link
|
struct wl_list pollFree; // WaylandPoll::link
|
||||||
LG_Lock pollLock;
|
LG_Lock pollLock;
|
||||||
LG_Lock pollFreeLock;
|
LG_Lock pollFreeLock;
|
||||||
unsigned int pollWaiters;
|
unsigned int pollWaiters;
|
||||||
int epollFd;
|
int epollFd;
|
||||||
int displayFd;
|
int displayFd;
|
||||||
|
LG_DSEventSource eventSource;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WCBTransfer
|
struct WCBTransfer
|
||||||
|
|||||||
@@ -443,6 +443,7 @@ static bool x11Init(const LG_DSInitParams params)
|
|||||||
x11InputInit(&x11.input, &inputSink, NULL);
|
x11InputInit(&x11.input, &inputSink, NULL);
|
||||||
LG_LOCK_INIT(x11.pointerLock);
|
LG_LOCK_INIT(x11.pointerLock);
|
||||||
atomic_init(&x11.captureActive, false);
|
atomic_init(&x11.captureActive, false);
|
||||||
|
x11.eventSource = params.eventSource;
|
||||||
x11.xValuator = -1;
|
x11.xValuator = -1;
|
||||||
x11.yValuator = -1;
|
x11.yValuator = -1;
|
||||||
x11.numLockIndicator = -1;
|
x11.numLockIndicator = -1;
|
||||||
@@ -1063,6 +1064,12 @@ static bool x11GetProp(LG_DSProperty prop, void *ret)
|
|||||||
|
|
||||||
static int x11EventThread(void * unused)
|
static int x11EventThread(void * unused)
|
||||||
{
|
{
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
EPOLL_SOURCE_X11,
|
||||||
|
EPOLL_SOURCE_EXTERNAL,
|
||||||
|
};
|
||||||
|
|
||||||
int epollfd = epoll_create1(0);
|
int epollfd = epoll_create1(0);
|
||||||
if (epollfd == -1)
|
if (epollfd == -1)
|
||||||
{
|
{
|
||||||
@@ -1070,7 +1077,11 @@ static int x11EventThread(void * unused)
|
|||||||
return 0;
|
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);
|
const int fd = ConnectionNumber(x11.display);
|
||||||
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1)
|
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1)
|
||||||
{
|
{
|
||||||
@@ -1079,6 +1090,18 @@ static int x11EventThread(void * unused)
|
|||||||
return 0;
|
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())
|
while(app_isRunning())
|
||||||
{
|
{
|
||||||
const uint64_t lastWMEvent = atomic_load(&x11.lastWMEvent);
|
const uint64_t lastWMEvent = atomic_load(&x11.lastWMEvent);
|
||||||
@@ -1088,24 +1111,30 @@ static int x11EventThread(void * unused)
|
|||||||
app_invalidateWindow(true);
|
app_invalidateWindow(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!XPending(x11.display))
|
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)
|
||||||
{
|
{
|
||||||
struct epoll_event events[1];
|
if (errno == EINTR)
|
||||||
int nfds = epoll_wait(epollfd, events, 1, 100);
|
|
||||||
if (nfds == -1)
|
|
||||||
{
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
close(epollfd);
|
|
||||||
DEBUG_ERROR("epoll_wait failure");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nfds == 0 || !XPending(x11.display))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
close(epollfd);
|
||||||
|
DEBUG_ERROR("epoll_wait failure");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
XEvent xe;
|
||||||
XNextEvent(x11.display, &xe);
|
XNextEvent(x11.display, &xe);
|
||||||
|
|
||||||
|
|||||||
@@ -101,10 +101,11 @@ struct X11DSState
|
|||||||
int xValuator;
|
int xValuator;
|
||||||
int yValuator;
|
int yValuator;
|
||||||
|
|
||||||
X11Input input;
|
X11Input input;
|
||||||
LG_Lock pointerLock;
|
LG_DSEventSource eventSource;
|
||||||
_Atomic(bool) captureActive;
|
LG_Lock pointerLock;
|
||||||
bool fullscreen;
|
_Atomic(bool) captureActive;
|
||||||
|
bool fullscreen;
|
||||||
|
|
||||||
struct Rect rect;
|
struct Rect rect;
|
||||||
struct Border border;
|
struct Border border;
|
||||||
|
|||||||
@@ -103,6 +103,18 @@ LG_DSWaitFrameResult;
|
|||||||
|
|
||||||
#define LG_POINTER_COUNT (LG_POINTER_NOT_ALLOWED + 1)
|
#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
|
typedef struct LG_DSInitParams
|
||||||
{
|
{
|
||||||
const char * title;
|
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
|
// x11 needs to know if this is in use so we can decide to setup for
|
||||||
// presentation times
|
// presentation times
|
||||||
bool jitRender;
|
bool jitRender;
|
||||||
|
|
||||||
|
LG_DSEventSource eventSource;
|
||||||
}
|
}
|
||||||
LG_DSInitParams;
|
LG_DSInitParams;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user