Refactor linux backend event loops
Allow waiting for events on an arbitrary number of fds. Needed for async DBUS integration.
This commit is contained in:
parent
3a4b614ae0
commit
e91eb27e56
115
glfw/backend_utils.c
vendored
Normal file
115
glfw/backend_utils.c
vendored
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* backend_utils.c
|
||||||
|
* Copyright (C) 2018 Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
*
|
||||||
|
* Distributed under terms of the GPL3 license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include "backend_utils.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#ifdef __NetBSD__
|
||||||
|
#define ppoll pollts
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
update_fds(EventLoopData *eld) {
|
||||||
|
eld->fds_count = 0;
|
||||||
|
for (nfds_t i = 0; i < eld->watches_count; i++) {
|
||||||
|
Watch *w = eld->watches + i;
|
||||||
|
if (w->enabled) {
|
||||||
|
eld->fds[eld->fds_count].fd = w->fd;
|
||||||
|
eld->fds[eld->fds_count].events = w->events;
|
||||||
|
eld->fds_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
addWatch(EventLoopData *eld, int fd, int events, int enabled, watch_callback_func cb, void *cb_data) {
|
||||||
|
removeWatch(eld, fd);
|
||||||
|
if (eld->watches_count >= sizeof(eld->watches)/sizeof(eld->watches[0])) return;
|
||||||
|
Watch *w = eld->watches + eld->watches_count++;
|
||||||
|
w->fd = fd; w->events = events; w->enabled = enabled;
|
||||||
|
w->callback = cb;
|
||||||
|
w->callback_data = cb_data;
|
||||||
|
update_fds(eld);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
removeWatch(EventLoopData *eld, int fd) {
|
||||||
|
for (nfds_t i = 0; i < eld->watches_count; i++) {
|
||||||
|
if (eld->watches[i].fd == fd) {
|
||||||
|
eld->watches_count--;
|
||||||
|
if (i < eld->watches_count) {
|
||||||
|
memmove(eld->watches + i, eld->watches + i + 1, sizeof(eld->watches[0]) * (eld->watches_count - i));
|
||||||
|
}
|
||||||
|
update_fds(eld);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
toggleWatch(EventLoopData *eld, int fd, int enabled) {
|
||||||
|
for (nfds_t i = 0; i < eld->watches_count; i++) {
|
||||||
|
if (eld->watches[i].fd == fd) {
|
||||||
|
if (eld->watches[i].enabled != enabled) {
|
||||||
|
eld->watches[i].enabled = enabled;
|
||||||
|
update_fds(eld);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
prepareForPoll(EventLoopData *eld) {
|
||||||
|
for (nfds_t i = 0; i < eld->fds_count; i++) eld->fds[i].revents = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pollWithTimeout(struct pollfd *fds, nfds_t nfds, double timeout) {
|
||||||
|
const long seconds = (long) timeout;
|
||||||
|
const long nanoseconds = (long) ((timeout - seconds) * 1e9);
|
||||||
|
struct timespec tv = { seconds, nanoseconds };
|
||||||
|
return ppoll(fds, nfds, &tv, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dispatchEvents(EventLoopData *eld) {
|
||||||
|
for (unsigned w = 0, f = 0; f < eld->fds_count; f++) {
|
||||||
|
while(eld->watches[w].fd != eld->fds[f].fd) w++;
|
||||||
|
Watch *ww = eld->watches + w;
|
||||||
|
if (eld->fds[f].revents & ww->events) {
|
||||||
|
ww->ready = 1;
|
||||||
|
if (ww->callback) ww->callback(ww->fd, eld->fds[f].revents, ww->callback_data);
|
||||||
|
} else ww->ready = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
drain_wakeup_fd(int fd, int events, void* data) {
|
||||||
|
static char drain_buf[64];
|
||||||
|
while(read(fd, drain_buf, sizeof(drain_buf)) < 0 && errno == EINTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
initPollData(EventLoopData *eld, int wakeup_fd, int display_fd) {
|
||||||
|
addWatch(eld, display_fd, POLLIN, 1, NULL, NULL);
|
||||||
|
addWatch(eld, wakeup_fd, POLLIN, 1, drain_wakeup_fd, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
closeFds(int *fds, size_t count) {
|
||||||
|
while(count--) {
|
||||||
|
if (*fds > 0) {
|
||||||
|
close(*fds);
|
||||||
|
*fds = -1;
|
||||||
|
}
|
||||||
|
fds++;
|
||||||
|
}
|
||||||
|
}
|
||||||
56
glfw/backend_utils.h
vendored
56
glfw/backend_utils.h
vendored
@ -25,42 +25,30 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <unistd.h>
|
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <errno.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#ifdef __NetBSD__
|
typedef void(*watch_callback_func)(int, int, void*);
|
||||||
#define ppoll pollts
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline void
|
typedef struct {
|
||||||
drainFd(int fd) {
|
int fd, events, enabled, ready;
|
||||||
static char drain_buf[64];
|
watch_callback_func callback;
|
||||||
while(read(fd, drain_buf, sizeof(drain_buf)) < 0 && errno == EINTR);
|
void *callback_data;
|
||||||
}
|
} Watch;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct pollfd fds[32];
|
||||||
|
int wakeupFds[2];
|
||||||
|
nfds_t watches_count, fds_count;
|
||||||
|
Watch watches[32];
|
||||||
|
} EventLoopData;
|
||||||
|
|
||||||
|
|
||||||
static inline int
|
void addWatch(EventLoopData *eld, int fd, int events, int enabled, watch_callback_func cb, void *cb_data);
|
||||||
pollWithTimeout(struct pollfd *fds, nfds_t nfds, double timeout) {
|
void removeWatch(EventLoopData *eld, int fd);
|
||||||
const long seconds = (long) timeout;
|
void toggleWatch(EventLoopData *eld, int fd, int enabled);
|
||||||
const long nanoseconds = (long) ((timeout - seconds) * 1e9);
|
void prepareForPoll(EventLoopData *eld);
|
||||||
struct timespec tv = { seconds, nanoseconds };
|
int pollWithTimeout(struct pollfd *fds, nfds_t nfds, double timeout);
|
||||||
return ppoll(fds, nfds, &tv, NULL);
|
void dispatchEvents(EventLoopData *eld);
|
||||||
}
|
void closeFds(int *fds, size_t count);
|
||||||
|
void initPollData(EventLoopData *eld, int wakeup_fd, int display_fd);
|
||||||
static inline void
|
|
||||||
initPollData(struct pollfd *fds, int wakeup_fd, int display_fd) {
|
|
||||||
fds[0].fd = wakeup_fd; fds[1].fd = display_fd;
|
|
||||||
fds[0].events = POLLIN; fds[1].events = POLLIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
closeFds(int *fds, size_t count) {
|
|
||||||
while(count--) {
|
|
||||||
if (*fds > 0) {
|
|
||||||
close(*fds);
|
|
||||||
*fds = -1;
|
|
||||||
}
|
|
||||||
fds++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -283,7 +283,6 @@ def main():
|
|||||||
for src in files_to_copy:
|
for src in files_to_copy:
|
||||||
shutil.copy2(src, '.')
|
shutil.copy2(src, '.')
|
||||||
shutil.copy2(glfw_header, '.')
|
shutil.copy2(glfw_header, '.')
|
||||||
patch_in_file('internal.h', lambda x: x.replace('../include/GLFW/', ''))
|
|
||||||
patch_in_file('cocoa_window.m', lambda x: re.sub(
|
patch_in_file('cocoa_window.m', lambda x: re.sub(
|
||||||
r'[(]void[)]loadMainMenu.+?}', '(void)loadMainMenu\n{ // removed by Kovid as it generated compiler warnings \n}\n', x, flags=re.DOTALL))
|
r'[(]void[)]loadMainMenu.+?}', '(void)loadMainMenu\n{ // removed by Kovid as it generated compiler warnings \n}\n', x, flags=re.DOTALL))
|
||||||
json.dump(
|
json.dump(
|
||||||
|
|||||||
@ -84,6 +84,7 @@
|
|||||||
"ibus_glfw.c",
|
"ibus_glfw.c",
|
||||||
"egl_context.c",
|
"egl_context.c",
|
||||||
"osmesa_context.c",
|
"osmesa_context.c",
|
||||||
|
"backend_utils.c",
|
||||||
"linux_joystick.c",
|
"linux_joystick.c",
|
||||||
"null_joystick.c"
|
"null_joystick.c"
|
||||||
]
|
]
|
||||||
@ -139,6 +140,7 @@
|
|||||||
"glx_context.c",
|
"glx_context.c",
|
||||||
"egl_context.c",
|
"egl_context.c",
|
||||||
"osmesa_context.c",
|
"osmesa_context.c",
|
||||||
|
"backend_utils.c",
|
||||||
"linux_joystick.c",
|
"linux_joystick.c",
|
||||||
"null_joystick.c"
|
"null_joystick.c"
|
||||||
]
|
]
|
||||||
|
|||||||
2
glfw/wl_init.c
vendored
2
glfw/wl_init.c
vendored
@ -664,7 +664,7 @@ int _glfwPlatformInit(void)
|
|||||||
"Wayland: Failed to connect to display");
|
"Wayland: Failed to connect to display");
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
}
|
}
|
||||||
initPollData(_glfw.wl.eventLoopData.fds, _glfw.wl.eventLoopData.wakeupFds[0], wl_display_get_fd(_glfw.wl.display));
|
initPollData(&_glfw.wl.eventLoopData, _glfw.wl.eventLoopData.wakeupFds[0], wl_display_get_fd(_glfw.wl.display));
|
||||||
|
|
||||||
_glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
|
_glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
|
||||||
wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL);
|
wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL);
|
||||||
|
|||||||
6
glfw/wl_platform.h
vendored
6
glfw/wl_platform.h
vendored
@ -49,6 +49,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
|
|||||||
#else
|
#else
|
||||||
#include "null_joystick.h"
|
#include "null_joystick.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "backend_utils.h"
|
||||||
#include "xkb_glfw.h"
|
#include "xkb_glfw.h"
|
||||||
#include "egl_context.h"
|
#include "egl_context.h"
|
||||||
#include "osmesa_context.h"
|
#include "osmesa_context.h"
|
||||||
@ -230,10 +231,7 @@ typedef struct _GLFWlibraryWayland
|
|||||||
PFN_wl_egl_window_resize window_resize;
|
PFN_wl_egl_window_resize window_resize;
|
||||||
} egl;
|
} egl;
|
||||||
|
|
||||||
struct {
|
EventLoopData eventLoopData;
|
||||||
struct pollfd fds[2];
|
|
||||||
int wakeupFds[2];
|
|
||||||
} eventLoopData;
|
|
||||||
|
|
||||||
} _GLFWlibraryWayland;
|
} _GLFWlibraryWayland;
|
||||||
|
|
||||||
|
|||||||
17
glfw/wl_window.c
vendored
17
glfw/wl_window.c
vendored
@ -735,19 +735,18 @@ handleEvents(double timeout)
|
|||||||
dispatchPendingKeyRepeats();
|
dispatchPendingKeyRepeats();
|
||||||
timeout = adjustTimeoutForKeyRepeat(timeout);
|
timeout = adjustTimeoutForKeyRepeat(timeout);
|
||||||
GLFWbool read_ok = GLFW_FALSE;
|
GLFWbool read_ok = GLFW_FALSE;
|
||||||
for (nfds_t i = 0; i < 2; i++) _glfw.wl.eventLoopData.fds[i].revents = 0;
|
prepareForPoll(&_glfw.wl.eventLoopData);
|
||||||
|
|
||||||
if (timeout >= 0) {
|
if (timeout >= 0) {
|
||||||
const int result = pollWithTimeout(_glfw.wl.eventLoopData.fds, 2, timeout);
|
const int result = pollWithTimeout(_glfw.wl.eventLoopData.fds, _glfw.wl.eventLoopData.fds_count, timeout);
|
||||||
if (result > 0)
|
if (result > 0) {
|
||||||
{
|
dispatchEvents(&_glfw.wl.eventLoopData);
|
||||||
if (_glfw.wl.eventLoopData.fds[0].revents & POLLIN) drainFd(_glfw.wl.eventLoopData.fds[0].fd);
|
read_ok = _glfw.wl.eventLoopData.watches[0].ready;
|
||||||
read_ok = _glfw.wl.eventLoopData.fds[1].revents & POLLIN;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (poll(_glfw.wl.eventLoopData.fds, 2, -1) > 0) {
|
if (poll(_glfw.wl.eventLoopData.fds, _glfw.wl.eventLoopData.fds_count, -1) > 0) {
|
||||||
if (_glfw.wl.eventLoopData.fds[0].revents & POLLIN) drainFd(_glfw.wl.eventLoopData.fds[0].fd);
|
dispatchEvents(&_glfw.wl.eventLoopData);
|
||||||
read_ok = _glfw.wl.eventLoopData.fds[1].revents & POLLIN;
|
read_ok = _glfw.wl.eventLoopData.watches[0].ready;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (read_ok) {
|
if (read_ok) {
|
||||||
|
|||||||
5
glfw/x11_init.c
vendored
5
glfw/x11_init.c
vendored
@ -640,8 +640,7 @@ int _glfwPlatformInit(void)
|
|||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
initPollData(_glfw.x11.eventLoopData.fds, _glfw.x11.eventLoopData.wakeupFds[0], ConnectionNumber(_glfw.x11.display));
|
initPollData(&_glfw.x11.eventLoopData, _glfw.x11.eventLoopData.wakeupFds[0], ConnectionNumber(_glfw.x11.display));
|
||||||
_glfw.x11.eventLoopData.fds[2].events = POLLIN;
|
|
||||||
|
|
||||||
_glfw.x11.screen = DefaultScreen(_glfw.x11.display);
|
_glfw.x11.screen = DefaultScreen(_glfw.x11.display);
|
||||||
_glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen);
|
_glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen);
|
||||||
@ -660,6 +659,8 @@ int _glfwPlatformInit(void)
|
|||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
if (!_glfwInitJoysticksLinux())
|
if (!_glfwInitJoysticksLinux())
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
|
if (_glfw.linjs.inotify > 0)
|
||||||
|
addWatch(&_glfw.x11.eventLoopData, _glfw.linjs.inotify, POLLIN, 1, NULL, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_glfwInitTimerPOSIX();
|
_glfwInitTimerPOSIX();
|
||||||
|
|||||||
6
glfw/x11_platform.h
vendored
6
glfw/x11_platform.h
vendored
@ -53,6 +53,7 @@
|
|||||||
|
|
||||||
// The libxkb library is used for improved keyboard support
|
// The libxkb library is used for improved keyboard support
|
||||||
#include "xkb_glfw.h"
|
#include "xkb_glfw.h"
|
||||||
|
#include "backend_utils.h"
|
||||||
|
|
||||||
typedef XRRCrtcGamma* (* PFN_XRRAllocGamma)(int);
|
typedef XRRCrtcGamma* (* PFN_XRRAllocGamma)(int);
|
||||||
typedef void (* PFN_XRRFreeCrtcInfo)(XRRCrtcInfo*);
|
typedef void (* PFN_XRRFreeCrtcInfo)(XRRCrtcInfo*);
|
||||||
@ -383,10 +384,7 @@ typedef struct _GLFWlibraryX11
|
|||||||
PFN_XRenderFindVisualFormat FindVisualFormat;
|
PFN_XRenderFindVisualFormat FindVisualFormat;
|
||||||
} xrender;
|
} xrender;
|
||||||
|
|
||||||
struct {
|
EventLoopData eventLoopData;
|
||||||
struct pollfd fds[3];
|
|
||||||
int wakeupFds[2];
|
|
||||||
} eventLoopData;
|
|
||||||
|
|
||||||
} _GLFWlibraryX11;
|
} _GLFWlibraryX11;
|
||||||
|
|
||||||
|
|||||||
21
glfw/x11_window.c
vendored
21
glfw/x11_window.c
vendored
@ -56,18 +56,11 @@
|
|||||||
//
|
//
|
||||||
static GLFWbool waitForEvent(double* timeout)
|
static GLFWbool waitForEvent(double* timeout)
|
||||||
{
|
{
|
||||||
nfds_t count = 2;
|
nfds_t count = _glfw.x11.eventLoopData.fds_count;
|
||||||
|
|
||||||
#if defined(__linux__)
|
|
||||||
if (_glfw.linjs.inotify > 0)
|
|
||||||
{
|
|
||||||
count = 3;
|
|
||||||
_glfw.x11.eventLoopData.fds[2].fd = _glfw.linjs.inotify;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
for (nfds_t i = 0; i < count; i++) _glfw.x11.eventLoopData.fds[i].revents = 0;
|
prepareForPoll(&_glfw.x11.eventLoopData);
|
||||||
if (timeout)
|
if (timeout)
|
||||||
{
|
{
|
||||||
const uint64_t base = _glfwPlatformGetTimerValue();
|
const uint64_t base = _glfwPlatformGetTimerValue();
|
||||||
@ -75,9 +68,8 @@ static GLFWbool waitForEvent(double* timeout)
|
|||||||
*timeout -= (_glfwPlatformGetTimerValue() - base) /
|
*timeout -= (_glfwPlatformGetTimerValue() - base) /
|
||||||
(double) _glfwPlatformGetTimerFrequency();
|
(double) _glfwPlatformGetTimerFrequency();
|
||||||
|
|
||||||
if (result > 0)
|
if (result > 0) {
|
||||||
{
|
dispatchEvents(&_glfw.x11.eventLoopData);
|
||||||
if (_glfw.x11.eventLoopData.fds[0].revents & POLLIN) drainFd(_glfw.x11.eventLoopData.fds[0].fd);
|
|
||||||
return GLFW_TRUE;
|
return GLFW_TRUE;
|
||||||
}
|
}
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
@ -87,9 +79,8 @@ static GLFWbool waitForEvent(double* timeout)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const int result = poll(_glfw.x11.eventLoopData.fds, count, -1);
|
const int result = poll(_glfw.x11.eventLoopData.fds, count, -1);
|
||||||
if (result > 0)
|
if (result > 0) {
|
||||||
{
|
dispatchEvents(&_glfw.x11.eventLoopData);
|
||||||
if (_glfw.x11.eventLoopData.fds[0].revents & POLLIN) drainFd(_glfw.x11.eventLoopData.fds[0].fd);
|
|
||||||
return GLFW_TRUE;
|
return GLFW_TRUE;
|
||||||
}
|
}
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user