Infrastructure for moving the run loop into GLFW
This is needed on Cocoa, where Apple expects to be in control of the run loop.
This commit is contained in:
parent
13254ac4d5
commit
da507dfd19
12 changed files with 129 additions and 6 deletions
23
glfw/backend_utils.c
vendored
23
glfw/backend_utils.c
vendored
|
|
@ -55,6 +55,7 @@ addWatch(EventLoopData *eld, const char* name, int fd, int events, int enabled,
|
|||
w->fd = fd; w->events = events; w->enabled = enabled;
|
||||
w->callback = cb;
|
||||
w->callback_data = cb_data;
|
||||
w->free = NULL;
|
||||
w->id = ++watch_counter;
|
||||
update_fds(eld);
|
||||
return w->id;
|
||||
|
|
@ -65,6 +66,10 @@ addWatch(EventLoopData *eld, const char* name, int fd, int events, int enabled,
|
|||
if (eld->which[i].id == item_id) { \
|
||||
eld->which##_count--; \
|
||||
if (i < eld->which##_count) { \
|
||||
if (eld->which[i].callback_data && eld->which[i].free) { \
|
||||
eld->which[i].free(eld->which[i].id, eld->which[i].callback_data); \
|
||||
eld->which[i].callback_data = NULL; eld->which[i].free = NULL; \
|
||||
} \
|
||||
memmove(eld->which + i, eld->which + i + 1, sizeof(eld->which[0]) * (eld->which##_count - i)); \
|
||||
} \
|
||||
update_func(eld); break; \
|
||||
|
|
@ -102,7 +107,7 @@ update_timers(EventLoopData *eld) {
|
|||
}
|
||||
|
||||
id_type
|
||||
addTimer(EventLoopData *eld, const char *name, double interval, int enabled, timer_callback_func cb, void *cb_data) {
|
||||
addTimer(EventLoopData *eld, const char *name, double interval, int enabled, bool repeats, timer_callback_func cb, void *cb_data, GLFWuserdatafreefun free) {
|
||||
if (eld->timers_count >= sizeof(eld->timers)/sizeof(eld->timers[0])) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many timers added");
|
||||
return 0;
|
||||
|
|
@ -111,8 +116,10 @@ addTimer(EventLoopData *eld, const char *name, double interval, int enabled, tim
|
|||
t->interval = interval;
|
||||
t->name = name;
|
||||
t->trigger_at = enabled ? monotonic() + interval : DBL_MAX;
|
||||
t->repeats = repeats;
|
||||
t->callback = cb;
|
||||
t->callback_data = cb_data;
|
||||
t->free = free;
|
||||
t->id = ++timer_counter;
|
||||
update_timers(eld);
|
||||
return t->id;
|
||||
|
|
@ -123,6 +130,14 @@ removeTimer(EventLoopData *eld, id_type timer_id) {
|
|||
removeX(timers, timer_id, update_timers);
|
||||
}
|
||||
|
||||
void
|
||||
removeAllTimers(EventLoopData *eld) {
|
||||
for (nfds_t i = 0; i < eld->timers_count; i++) {
|
||||
if (eld->timers[i].free && eld->timers[i].callback_data) eld->timers[i].free(eld->timers[i].id, eld->timers[i].callback_data);
|
||||
}
|
||||
eld->timers_count = 0;
|
||||
}
|
||||
|
||||
void
|
||||
toggleTimer(EventLoopData *eld, id_type timer_id, int enabled) {
|
||||
for (nfds_t i = 0; i < eld->timers_count; i++) {
|
||||
|
|
@ -182,7 +197,7 @@ dispatchEvents(EventLoopData *eld) {
|
|||
unsigned
|
||||
dispatchTimers(EventLoopData *eld) {
|
||||
if (!eld->timers_count || eld->timers[0].trigger_at == DBL_MAX) return 0;
|
||||
static struct { timer_callback_func func; id_type id; void* data; } dispatches[sizeof(eld->timers)/sizeof(eld->timers[0])];
|
||||
static struct { timer_callback_func func; id_type id; void* data; bool repeats; } dispatches[sizeof(eld->timers)/sizeof(eld->timers[0])];
|
||||
unsigned num_dispatches = 0;
|
||||
double now = monotonic();
|
||||
for (nfds_t i = 0; i < eld->timers_count && eld->timers[i].trigger_at <= now; i++) {
|
||||
|
|
@ -190,11 +205,15 @@ dispatchTimers(EventLoopData *eld) {
|
|||
dispatches[num_dispatches].func = eld->timers[i].callback;
|
||||
dispatches[num_dispatches].id = eld->timers[i].id;
|
||||
dispatches[num_dispatches].data = eld->timers[i].callback_data;
|
||||
dispatches[num_dispatches].repeats = eld->timers[i].repeats;
|
||||
num_dispatches++;
|
||||
}
|
||||
// we dispatch separately so that the callbacks can modify timers
|
||||
for (unsigned i = 0; i < num_dispatches; i++) {
|
||||
dispatches[i].func(dispatches[i].id, dispatches[i].data);
|
||||
if (!dispatches[i].repeats) {
|
||||
removeTimer(eld, dispatches[i].id);
|
||||
}
|
||||
}
|
||||
if (num_dispatches) update_timers(eld);
|
||||
return num_dispatches;
|
||||
|
|
|
|||
8
glfw/backend_utils.h
vendored
8
glfw/backend_utils.h
vendored
|
|
@ -27,15 +27,18 @@
|
|||
#pragma once
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef unsigned long long id_type;
|
||||
typedef void(*watch_callback_func)(int, int, void*);
|
||||
typedef void(*timer_callback_func)(id_type, void*);
|
||||
typedef void (* GLFWuserdatafreefun)(id_type, void*);
|
||||
|
||||
typedef struct {
|
||||
int fd, events, enabled, ready;
|
||||
watch_callback_func callback;
|
||||
void *callback_data;
|
||||
GLFWuserdatafreefun free;
|
||||
id_type id;
|
||||
const char *name;
|
||||
} Watch;
|
||||
|
|
@ -45,7 +48,9 @@ typedef struct {
|
|||
double interval, trigger_at;
|
||||
timer_callback_func callback;
|
||||
void *callback_data;
|
||||
GLFWuserdatafreefun free;
|
||||
const char *name;
|
||||
bool repeats;
|
||||
} Timer;
|
||||
|
||||
|
||||
|
|
@ -61,8 +66,9 @@ typedef struct {
|
|||
id_type addWatch(EventLoopData *eld, const char *name, int fd, int events, int enabled, watch_callback_func cb, void *cb_data);
|
||||
void removeWatch(EventLoopData *eld, id_type watch_id);
|
||||
void toggleWatch(EventLoopData *eld, id_type watch_id, int enabled);
|
||||
id_type addTimer(EventLoopData *eld, const char *name, double interval, int enabled, timer_callback_func cb, void *cb_data);
|
||||
id_type addTimer(EventLoopData *eld, const char *name, double interval, int enabled, bool repeats, timer_callback_func cb, void *cb_data, GLFWuserdatafreefun free);
|
||||
void removeTimer(EventLoopData *eld, id_type timer_id);
|
||||
void removeAllTimers(EventLoopData *eld);
|
||||
void toggleTimer(EventLoopData *eld, id_type timer_id, int enabled);
|
||||
void changeTimerInterval(EventLoopData *eld, id_type timer_id, double interval);
|
||||
double prepareForPoll(EventLoopData *eld, double timeout);
|
||||
|
|
|
|||
2
glfw/dbus_glfw.c
vendored
2
glfw/dbus_glfw.c
vendored
|
|
@ -109,7 +109,7 @@ add_dbus_timeout(DBusTimeout *timeout, void *data) {
|
|||
int enabled = dbus_timeout_get_enabled(timeout) ? 1 : 0;
|
||||
double interval = ((double)dbus_timeout_get_interval(timeout)) / 1000.0;
|
||||
if (interval < 0) return FALSE;
|
||||
id_type timer_id = addTimer(dbus_data->eld, data, interval, enabled, on_dbus_timer_ready, timeout);
|
||||
id_type timer_id = addTimer(dbus_data->eld, data, interval, enabled, true, on_dbus_timer_ready, timeout, NULL);
|
||||
if (!timer_id) return FALSE;
|
||||
id_type *idp = malloc(sizeof(id_type));
|
||||
if (!idp) {
|
||||
|
|
|
|||
6
glfw/glfw3.h
vendored
6
glfw/glfw3.h
vendored
|
|
@ -1509,6 +1509,8 @@ typedef void (* GLFWmonitorfun)(GLFWmonitor*,int);
|
|||
*/
|
||||
typedef void (* GLFWjoystickfun)(int,int);
|
||||
|
||||
typedef void (* GLFWuserdatafun)(unsigned long long, void*);
|
||||
|
||||
/*! @brief Video mode type.
|
||||
*
|
||||
* This describes a single video mode.
|
||||
|
|
@ -1655,6 +1657,10 @@ typedef struct GLFWgamepadstate
|
|||
* @ingroup init
|
||||
*/
|
||||
GLFWAPI int glfwInit(void);
|
||||
GLFWAPI void glfwRunMainLoop(void);
|
||||
GLFWAPI void glfwStopMainLoop(void);
|
||||
GLFWAPI unsigned long long glfwAddTimer(double interval, bool repeats, GLFWuserdatafun callback, void * callback_data, GLFWuserdatafun free_callback);
|
||||
GLFWAPI void glfwRemoveTimer(unsigned long long);
|
||||
|
||||
/*! @brief Terminates the GLFW library.
|
||||
*
|
||||
|
|
|
|||
20
glfw/init.c
vendored
20
glfw/init.c
vendored
|
|
@ -320,3 +320,23 @@ GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun)
|
|||
_GLFW_SWAP_POINTERS(_glfwErrorCallback, cbfun);
|
||||
return cbfun;
|
||||
}
|
||||
|
||||
|
||||
GLFWAPI void glfwRunMainLoop(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT();
|
||||
_glfwPlatformRunMainLoop();
|
||||
}
|
||||
|
||||
GLFWAPI void glfwStopMainLoop(void) {
|
||||
_GLFW_REQUIRE_INIT();
|
||||
_glfwPlatformStopMainLoop();
|
||||
}
|
||||
|
||||
GLFWAPI unsigned long long glfwAddTimer(double interval, bool repeats, GLFWuserdatafun callback, void *callback_data, GLFWuserdatafun free_callback) {
|
||||
return _glfwPlatformAddTimer(interval, repeats, callback, callback_data, free_callback);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwRemoveTimer(unsigned long long timer_id) {
|
||||
_glfwPlatformRemoveTimer(timer_id);
|
||||
}
|
||||
|
|
|
|||
4
glfw/internal.h
vendored
4
glfw/internal.h
vendored
|
|
@ -783,5 +783,9 @@ void _glfwTerminateVulkan(void);
|
|||
const char* _glfwGetVulkanResultString(VkResult result);
|
||||
_GLFWwindow* _glfwFocusedWindow();
|
||||
_GLFWwindow* _glfwWindowForId(GLFWid id);
|
||||
void _glfwPlatformRunMainLoop(void);
|
||||
void _glfwPlatformStopMainLoop(void);
|
||||
unsigned long long _glfwPlatformAddTimer(double interval, bool repeats, GLFWuserdatafreefun callback, void *callback_data, GLFWuserdatafreefun free_callback);
|
||||
void _glfwPlatformRemoveTimer(unsigned long long timer_id);
|
||||
|
||||
char* _glfw_strdup(const char* source);
|
||||
|
|
|
|||
4
glfw/wl_init.c
vendored
4
glfw/wl_init.c
vendored
|
|
@ -711,8 +711,8 @@ int _glfwPlatformInit(void)
|
|||
}
|
||||
initPollData(&_glfw.wl.eventLoopData, _glfw.wl.eventLoopData.wakeupFds[0], wl_display_get_fd(_glfw.wl.display));
|
||||
glfw_dbus_init(&_glfw.wl.dbus, &_glfw.wl.eventLoopData);
|
||||
_glfw.wl.keyRepeatInfo.keyRepeatTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-key-repeat", 0.5, 0, dispatchPendingKeyRepeats, NULL);
|
||||
_glfw.wl.cursorAnimationTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-cursor-animation", 0.5, 0, animateCursorImage, NULL);
|
||||
_glfw.wl.keyRepeatInfo.keyRepeatTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-key-repeat", 0.5, 0, true, dispatchPendingKeyRepeats, NULL, NULL);
|
||||
_glfw.wl.cursorAnimationTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-cursor-animation", 0.5, 0, true, animateCursorImage, NULL, NULL);
|
||||
|
||||
_glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
|
||||
wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL);
|
||||
|
|
|
|||
25
glfw/x11_init.c
vendored
25
glfw/x11_init.c
vendored
|
|
@ -675,6 +675,7 @@ int _glfwPlatformInit(void)
|
|||
|
||||
void _glfwPlatformTerminate(void)
|
||||
{
|
||||
removeAllTimers(&_glfw.x11.eventLoopData);
|
||||
if (_glfw.x11.helperWindowHandle)
|
||||
{
|
||||
if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) ==
|
||||
|
|
@ -768,3 +769,27 @@ const char* _glfwPlatformGetVersionString(void)
|
|||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
static GLFWbool keep_going;
|
||||
|
||||
void _glfwPlatformStopMainLoop(void) {
|
||||
if (keep_going) {
|
||||
keep_going = GLFW_FALSE;
|
||||
_glfwPlatformPostEmptyEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformRunMainLoop(void) {
|
||||
keep_going = GLFW_TRUE;
|
||||
while(keep_going) {
|
||||
_glfwPlatformWaitEvents();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long long _glfwPlatformAddTimer(double interval, bool repeats, GLFWuserdatafreefun callback, void *callback_data, GLFWuserdatafreefun free_callback) {
|
||||
return addTimer(&_glfw.x11.eventLoopData, "user timer", interval, 1, repeats, callback, callback_data, free_callback);
|
||||
}
|
||||
|
||||
void _glfwRemoveTimer(unsigned long long timer_id) {
|
||||
removeTimer(&_glfw.x11.eventLoopData, timer_id);
|
||||
}
|
||||
|
|
|
|||
12
kitty/glfw-wrapper.c
generated
12
kitty/glfw-wrapper.c
generated
|
|
@ -17,6 +17,18 @@ load_glfw(const char* path) {
|
|||
*(void **) (&glfwInit_impl) = dlsym(handle, "glfwInit");
|
||||
if (glfwInit_impl == NULL) fail("Failed to load glfw function glfwInit with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwRunMainLoop_impl) = dlsym(handle, "glfwRunMainLoop");
|
||||
if (glfwRunMainLoop_impl == NULL) fail("Failed to load glfw function glfwRunMainLoop with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwStopMainLoop_impl) = dlsym(handle, "glfwStopMainLoop");
|
||||
if (glfwStopMainLoop_impl == NULL) fail("Failed to load glfw function glfwStopMainLoop with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwAddTimer_impl) = dlsym(handle, "glfwAddTimer");
|
||||
if (glfwAddTimer_impl == NULL) fail("Failed to load glfw function glfwAddTimer with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwRemoveTimer_impl) = dlsym(handle, "glfwRemoveTimer");
|
||||
if (glfwRemoveTimer_impl == NULL) fail("Failed to load glfw function glfwRemoveTimer with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwTerminate_impl) = dlsym(handle, "glfwTerminate");
|
||||
if (glfwTerminate_impl == NULL) fail("Failed to load glfw function glfwTerminate with error: %s", dlerror());
|
||||
|
||||
|
|
|
|||
18
kitty/glfw-wrapper.h
generated
18
kitty/glfw-wrapper.h
generated
|
|
@ -1266,6 +1266,8 @@ typedef void (* GLFWmonitorfun)(GLFWmonitor*,int);
|
|||
*/
|
||||
typedef void (* GLFWjoystickfun)(int,int);
|
||||
|
||||
typedef void (* GLFWuserdatafun)(unsigned long long, void*);
|
||||
|
||||
/*! @brief Video mode type.
|
||||
*
|
||||
* This describes a single video mode.
|
||||
|
|
@ -1424,6 +1426,22 @@ typedef int (*glfwInit_func)();
|
|||
glfwInit_func glfwInit_impl;
|
||||
#define glfwInit glfwInit_impl
|
||||
|
||||
typedef void (*glfwRunMainLoop_func)();
|
||||
glfwRunMainLoop_func glfwRunMainLoop_impl;
|
||||
#define glfwRunMainLoop glfwRunMainLoop_impl
|
||||
|
||||
typedef void (*glfwStopMainLoop_func)();
|
||||
glfwStopMainLoop_func glfwStopMainLoop_impl;
|
||||
#define glfwStopMainLoop glfwStopMainLoop_impl
|
||||
|
||||
typedef unsigned long long (*glfwAddTimer_func)(double, bool, GLFWuserdatafun, void *, GLFWuserdatafun);
|
||||
glfwAddTimer_func glfwAddTimer_impl;
|
||||
#define glfwAddTimer glfwAddTimer_impl
|
||||
|
||||
typedef void (*glfwRemoveTimer_func)(unsigned long);
|
||||
glfwRemoveTimer_func glfwRemoveTimer_impl;
|
||||
#define glfwRemoveTimer glfwRemoveTimer_impl
|
||||
|
||||
typedef void (*glfwTerminate_func)();
|
||||
glfwTerminate_func glfwTerminate_impl;
|
||||
#define glfwTerminate glfwTerminate_impl
|
||||
|
|
|
|||
10
kitty/glfw.c
10
kitty/glfw.c
|
|
@ -1113,6 +1113,16 @@ dbus_send_notification(PyObject *self UNUSED, PyObject *args) {
|
|||
}
|
||||
#endif
|
||||
|
||||
id_type
|
||||
add_main_loop_timer(double interval, bool repeats, timer_callback_fun callback, void *callback_data, timer_callback_fun free_callback) {
|
||||
return glfwAddTimer(interval, repeats, callback, callback_data, free_callback);
|
||||
}
|
||||
|
||||
void
|
||||
remove_main_loop_timer(id_type timer_id) {
|
||||
glfwRemoveTimer(timer_id);
|
||||
}
|
||||
|
||||
// Boilerplate {{{
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
|
|
|
|||
|
|
@ -221,3 +221,6 @@ bool application_quit_requested();
|
|||
void request_application_quit();
|
||||
#endif
|
||||
void request_frame_render(OSWindow *w);
|
||||
typedef void (* timer_callback_fun)(id_type, void*);
|
||||
id_type add_main_loop_timer(double interval, bool repeats, timer_callback_fun callback, void *callback_data, timer_callback_fun free_callback);
|
||||
void remove_main_loop_timer(id_type timer_id);
|
||||
|
|
|
|||
Loading…
Reference in a new issue