diff --git a/glfw/backend_utils.c b/glfw/backend_utils.c new file mode 100644 index 000000000..4c42c29a5 --- /dev/null +++ b/glfw/backend_utils.c @@ -0,0 +1,115 @@ +/* + * backend_utils.c + * Copyright (C) 2018 Kovid Goyal + * + * Distributed under terms of the GPL3 license. + */ + +#define _GNU_SOURCE +#include "backend_utils.h" + +#include +#include + +#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++; + } +} diff --git a/glfw/backend_utils.h b/glfw/backend_utils.h index d7b63d3aa..b2db23448 100644 --- a/glfw/backend_utils.h +++ b/glfw/backend_utils.h @@ -25,42 +25,30 @@ //======================================================================== #pragma once -#include #include -#include +#include -#ifdef __NetBSD__ -#define ppoll pollts -#endif +typedef void(*watch_callback_func)(int, int, void*); -static inline void -drainFd(int fd) { - static char drain_buf[64]; - while(read(fd, drain_buf, sizeof(drain_buf)) < 0 && errno == EINTR); -} +typedef struct { + int fd, events, enabled, ready; + watch_callback_func callback; + 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 -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); -} - -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++; - } -} +void addWatch(EventLoopData *eld, int fd, int events, int enabled, watch_callback_func cb, void *cb_data); +void removeWatch(EventLoopData *eld, int fd); +void toggleWatch(EventLoopData *eld, int fd, int enabled); +void prepareForPoll(EventLoopData *eld); +int pollWithTimeout(struct pollfd *fds, nfds_t nfds, double timeout); +void dispatchEvents(EventLoopData *eld); +void closeFds(int *fds, size_t count); +void initPollData(EventLoopData *eld, int wakeup_fd, int display_fd); diff --git a/glfw/glfw.py b/glfw/glfw.py index 681f5311a..f2e52c128 100755 --- a/glfw/glfw.py +++ b/glfw/glfw.py @@ -283,7 +283,6 @@ def main(): for src in files_to_copy: shutil.copy2(src, '.') 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( r'[(]void[)]loadMainMenu.+?}', '(void)loadMainMenu\n{ // removed by Kovid as it generated compiler warnings \n}\n', x, flags=re.DOTALL)) json.dump( diff --git a/glfw/source-info.json b/glfw/source-info.json index 76339916f..2f832403c 100644 --- a/glfw/source-info.json +++ b/glfw/source-info.json @@ -84,6 +84,7 @@ "ibus_glfw.c", "egl_context.c", "osmesa_context.c", + "backend_utils.c", "linux_joystick.c", "null_joystick.c" ] @@ -139,6 +140,7 @@ "glx_context.c", "egl_context.c", "osmesa_context.c", + "backend_utils.c", "linux_joystick.c", "null_joystick.c" ] diff --git a/glfw/wl_init.c b/glfw/wl_init.c index cf4b9a496..b1a0f5a7e 100644 --- a/glfw/wl_init.c +++ b/glfw/wl_init.c @@ -664,7 +664,7 @@ int _glfwPlatformInit(void) "Wayland: Failed to connect to display"); 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); wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL); diff --git a/glfw/wl_platform.h b/glfw/wl_platform.h index 21683a849..fe5a5f3a5 100644 --- a/glfw/wl_platform.h +++ b/glfw/wl_platform.h @@ -49,6 +49,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR #else #include "null_joystick.h" #endif +#include "backend_utils.h" #include "xkb_glfw.h" #include "egl_context.h" #include "osmesa_context.h" @@ -230,10 +231,7 @@ typedef struct _GLFWlibraryWayland PFN_wl_egl_window_resize window_resize; } egl; - struct { - struct pollfd fds[2]; - int wakeupFds[2]; - } eventLoopData; + EventLoopData eventLoopData; } _GLFWlibraryWayland; diff --git a/glfw/wl_window.c b/glfw/wl_window.c index 10c9bf5c1..39aef9199 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -735,19 +735,18 @@ handleEvents(double timeout) dispatchPendingKeyRepeats(); timeout = adjustTimeoutForKeyRepeat(timeout); 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) { - const int result = pollWithTimeout(_glfw.wl.eventLoopData.fds, 2, timeout); - if (result > 0) - { - if (_glfw.wl.eventLoopData.fds[0].revents & POLLIN) drainFd(_glfw.wl.eventLoopData.fds[0].fd); - read_ok = _glfw.wl.eventLoopData.fds[1].revents & POLLIN; + const int result = pollWithTimeout(_glfw.wl.eventLoopData.fds, _glfw.wl.eventLoopData.fds_count, timeout); + if (result > 0) { + dispatchEvents(&_glfw.wl.eventLoopData); + read_ok = _glfw.wl.eventLoopData.watches[0].ready; } } else { - if (poll(_glfw.wl.eventLoopData.fds, 2, -1) > 0) { - if (_glfw.wl.eventLoopData.fds[0].revents & POLLIN) drainFd(_glfw.wl.eventLoopData.fds[0].fd); - read_ok = _glfw.wl.eventLoopData.fds[1].revents & POLLIN; + if (poll(_glfw.wl.eventLoopData.fds, _glfw.wl.eventLoopData.fds_count, -1) > 0) { + dispatchEvents(&_glfw.wl.eventLoopData); + read_ok = _glfw.wl.eventLoopData.watches[0].ready; } } if (read_ok) { diff --git a/glfw/x11_init.c b/glfw/x11_init.c index d2837c75e..c9939d4f4 100644 --- a/glfw/x11_init.c +++ b/glfw/x11_init.c @@ -640,8 +640,7 @@ int _glfwPlatformInit(void) return GLFW_FALSE; } - initPollData(_glfw.x11.eventLoopData.fds, _glfw.x11.eventLoopData.wakeupFds[0], ConnectionNumber(_glfw.x11.display)); - _glfw.x11.eventLoopData.fds[2].events = POLLIN; + initPollData(&_glfw.x11.eventLoopData, _glfw.x11.eventLoopData.wakeupFds[0], ConnectionNumber(_glfw.x11.display)); _glfw.x11.screen = DefaultScreen(_glfw.x11.display); _glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen); @@ -660,6 +659,8 @@ int _glfwPlatformInit(void) #if defined(__linux__) if (!_glfwInitJoysticksLinux()) return GLFW_FALSE; + if (_glfw.linjs.inotify > 0) + addWatch(&_glfw.x11.eventLoopData, _glfw.linjs.inotify, POLLIN, 1, NULL, NULL); #endif _glfwInitTimerPOSIX(); diff --git a/glfw/x11_platform.h b/glfw/x11_platform.h index b3faa2b29..c1b49907a 100644 --- a/glfw/x11_platform.h +++ b/glfw/x11_platform.h @@ -53,6 +53,7 @@ // The libxkb library is used for improved keyboard support #include "xkb_glfw.h" +#include "backend_utils.h" typedef XRRCrtcGamma* (* PFN_XRRAllocGamma)(int); typedef void (* PFN_XRRFreeCrtcInfo)(XRRCrtcInfo*); @@ -383,10 +384,7 @@ typedef struct _GLFWlibraryX11 PFN_XRenderFindVisualFormat FindVisualFormat; } xrender; - struct { - struct pollfd fds[3]; - int wakeupFds[2]; - } eventLoopData; + EventLoopData eventLoopData; } _GLFWlibraryX11; diff --git a/glfw/x11_window.c b/glfw/x11_window.c index ab3fcb4d7..1b489e23f 100644 --- a/glfw/x11_window.c +++ b/glfw/x11_window.c @@ -56,18 +56,11 @@ // 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 (nfds_t i = 0; i < count; i++) _glfw.x11.eventLoopData.fds[i].revents = 0; + prepareForPoll(&_glfw.x11.eventLoopData); if (timeout) { const uint64_t base = _glfwPlatformGetTimerValue(); @@ -75,9 +68,8 @@ static GLFWbool waitForEvent(double* timeout) *timeout -= (_glfwPlatformGetTimerValue() - base) / (double) _glfwPlatformGetTimerFrequency(); - if (result > 0) - { - if (_glfw.x11.eventLoopData.fds[0].revents & POLLIN) drainFd(_glfw.x11.eventLoopData.fds[0].fd); + if (result > 0) { + dispatchEvents(&_glfw.x11.eventLoopData); return GLFW_TRUE; } if (result == 0) @@ -87,9 +79,8 @@ static GLFWbool waitForEvent(double* timeout) } else { const int result = poll(_glfw.x11.eventLoopData.fds, count, -1); - if (result > 0) - { - if (_glfw.x11.eventLoopData.fds[0].revents & POLLIN) drainFd(_glfw.x11.eventLoopData.fds[0].fd); + if (result > 0) { + dispatchEvents(&_glfw.x11.eventLoopData); return GLFW_TRUE; } if (result == 0)