From f3b9ff5f9fd527d7e08dad3fef130cacd9d44d29 Mon Sep 17 00:00:00 2001 From: Luflosi Date: Fri, 2 Aug 2019 11:49:02 -0500 Subject: [PATCH] Use datatype monotonic_t instead of double to keep track of time The time is stored in a signed 64 bit integer with nanosecond accuracy. This eliminates the possibility of floating-point inaccuracies. `monotonic_t` can currently hold values large enough to work correctly for more than 200 years into the future. Using a typedef instead of directly using `int64_t` everywhere will also allow easily changing the datatype in the future should the need arise for more precise or bigger time values. --- glfw/backend_utils.c | 45 ++++++++--------------- glfw/backend_utils.h | 13 +++---- glfw/cocoa_init.m | 9 ++--- glfw/cocoa_platform.h | 2 +- glfw/cocoa_window.m | 9 ++--- glfw/dbus_glfw.c | 3 +- glfw/glfw3.h | 10 +++--- glfw/init.c | 6 ++-- glfw/input.c | 17 +++++---- glfw/internal.h | 10 +++--- glfw/main_loop.h | 5 +-- glfw/null_window.c | 7 ++-- glfw/window.c | 5 +-- glfw/wl_init.c | 11 +++--- glfw/wl_platform.h | 2 +- glfw/wl_window.c | 23 ++++++------ glfw/x11_window.c | 35 +++++++++--------- kitty/child-monitor.c | 65 ++++++++++++++++----------------- kitty/cocoa_window.m | 5 +-- kitty/data-types.c | 44 ++--------------------- kitty/data-types.h | 1 - kitty/glfw-wrapper.h | 11 +++--- kitty/glfw.c | 33 ++++++++--------- kitty/graphics.c | 2 +- kitty/graphics.h | 3 +- kitty/kittens.c | 7 ++-- kitty/monotonic.h | 84 +++++++++++++++++++++++++++++++++++++++++++ kitty/mouse.c | 7 ++-- kitty/parser.c | 5 +-- kitty/screen.c | 2 +- kitty/screen.h | 11 +++--- kitty/state.c | 27 ++++++++------ kitty/state.h | 22 ++++++------ 33 files changed, 298 insertions(+), 243 deletions(-) create mode 100644 kitty/monotonic.h diff --git a/glfw/backend_utils.c b/glfw/backend_utils.c index 9058c6c37..536dbdb1c 100644 --- a/glfw/backend_utils.c +++ b/glfw/backend_utils.c @@ -22,19 +22,6 @@ #define ppoll pollts #endif -static inline double -monotonic(void) { - struct timespec ts = {0}; -#ifdef CLOCK_HIGHRES - clock_gettime(CLOCK_HIGHRES, &ts); -#elif CLOCK_MONOTONIC_RAW - clock_gettime(CLOCK_MONOTONIC_RAW, &ts); -#else - clock_gettime(CLOCK_MONOTONIC, &ts); -#endif - return (((double)ts.tv_nsec) / 1e9) + (double)ts.tv_sec; -} - void update_fds(EventLoopData *eld) { for (nfds_t i = 0; i < eld->watches_count; i++) { @@ -109,7 +96,7 @@ update_timers(EventLoopData *eld) { } id_type -addTimer(EventLoopData *eld, const char *name, double interval, int enabled, bool repeats, timer_callback_func cb, void *cb_data, GLFWuserdatafreefun free) { +addTimer(EventLoopData *eld, const char *name, monotonic_t 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; @@ -117,7 +104,7 @@ addTimer(EventLoopData *eld, const char *name, double interval, int enabled, boo Timer *t = eld->timers + eld->timers_count++; t->interval = interval; t->name = name; - t->trigger_at = enabled ? monotonic() + interval : DBL_MAX; + t->trigger_at = enabled ? monotonic() + interval : MONOTONIC_T_MAX; t->repeats = repeats; t->callback = cb; t->callback_data = cb_data; @@ -144,7 +131,7 @@ void toggleTimer(EventLoopData *eld, id_type timer_id, int enabled) { for (nfds_t i = 0; i < eld->timers_count; i++) { if (eld->timers[i].id == timer_id) { - double trigger_at = enabled ? (monotonic() + eld->timers[i].interval) : DBL_MAX; + monotonic_t trigger_at = enabled ? (monotonic() + eld->timers[i].interval) : MONOTONIC_T_MAX; if (trigger_at != eld->timers[i].trigger_at) { eld->timers[i].trigger_at = trigger_at; update_timers(eld); @@ -155,7 +142,7 @@ toggleTimer(EventLoopData *eld, id_type timer_id, int enabled) { } void -changeTimerInterval(EventLoopData *eld, id_type timer_id, double interval) { +changeTimerInterval(EventLoopData *eld, id_type timer_id, monotonic_t interval) { for (nfds_t i = 0; i < eld->timers_count; i++) { if (eld->timers[i].id == timer_id) { eld->timers[i].interval = interval; @@ -165,11 +152,11 @@ changeTimerInterval(EventLoopData *eld, id_type timer_id, double interval) { } -double -prepareForPoll(EventLoopData *eld, double timeout) { +monotonic_t +prepareForPoll(EventLoopData *eld, monotonic_t timeout) { for (nfds_t i = 0; i < eld->watches_count; i++) eld->fds[i].revents = 0; - if (!eld->timers_count || eld->timers[0].trigger_at == DBL_MAX) return timeout; - double now = monotonic(), next_repeat_at = eld->timers[0].trigger_at; + if (!eld->timers_count || eld->timers[0].trigger_at == MONOTONIC_T_MAX) return timeout; + monotonic_t now = monotonic(), next_repeat_at = eld->timers[0].trigger_at; if (timeout < 0 || now + timeout > next_repeat_at) { timeout = next_repeat_at <= now ? 0 : next_repeat_at - now; } @@ -177,10 +164,8 @@ prepareForPoll(EventLoopData *eld, double timeout) { } 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 }; +pollWithTimeout(struct pollfd *fds, nfds_t nfds, monotonic_t timeout) { + struct timespec tv = calc_time(timeout); return ppoll(fds, nfds, &tv, NULL); } @@ -198,10 +183,10 @@ dispatchEvents(EventLoopData *eld) { unsigned dispatchTimers(EventLoopData *eld) { - if (!eld->timers_count || eld->timers[0].trigger_at == DBL_MAX) return 0; + if (!eld->timers_count || eld->timers[0].trigger_at == MONOTONIC_T_MAX) return 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(); + monotonic_t now = monotonic(); for (nfds_t i = 0; i < eld->timers_count && eld->timers[i].trigger_at <= now; i++) { eld->timers[i].trigger_at = now + eld->timers[i].interval; dispatches[num_dispatches].func = eld->timers[i].callback; @@ -299,12 +284,12 @@ finalizePollData(EventLoopData *eld) { } int -pollForEvents(EventLoopData *eld, double timeout) { +pollForEvents(EventLoopData *eld, monotonic_t timeout) { int read_ok = 0; timeout = prepareForPoll(eld, timeout); - EVDBG("pollForEvents final timeout: %.3f", timeout); + EVDBG("pollForEvents final timeout: %.3f", monotonic_t_to_s_double(timeout)); int result; - double end_time = monotonic() + timeout; + monotonic_t end_time = monotonic() + timeout; eld->wakeup_fd_ready = false; while(1) { diff --git a/glfw/backend_utils.h b/glfw/backend_utils.h index 154458170..3e1ff2abe 100644 --- a/glfw/backend_utils.h +++ b/glfw/backend_utils.h @@ -25,6 +25,7 @@ //======================================================================== #pragma once +#include "../kitty/monotonic.h" #include #include #include @@ -55,7 +56,7 @@ typedef struct { typedef struct { id_type id; - double interval, trigger_at; + monotonic_t interval, trigger_at; timer_callback_func callback; void *callback_data; GLFWuserdatafreefun free; @@ -82,14 +83,14 @@ void check_for_wakeup_events(EventLoopData *eld); 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, bool repeats, timer_callback_func cb, void *cb_data, GLFWuserdatafreefun free); +id_type addTimer(EventLoopData *eld, const char *name, monotonic_t 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); -int pollWithTimeout(struct pollfd *fds, nfds_t nfds, double timeout); -int pollForEvents(EventLoopData *eld, double timeout); +void changeTimerInterval(EventLoopData *eld, id_type timer_id, monotonic_t interval); +monotonic_t prepareForPoll(EventLoopData *eld, monotonic_t timeout); +int pollWithTimeout(struct pollfd *fds, nfds_t nfds, monotonic_t timeout); +int pollForEvents(EventLoopData *eld, monotonic_t timeout); unsigned dispatchTimers(EventLoopData *eld); void finalizePollData(EventLoopData *eld); bool initPollData(EventLoopData *eld, int display_fd); diff --git a/glfw/cocoa_init.m b/glfw/cocoa_init.m index d8b12057f..867ae82a5 100644 --- a/glfw/cocoa_init.m +++ b/glfw/cocoa_init.m @@ -27,6 +27,7 @@ //======================================================================== #include "internal.h" +#include "../kitty/monotonic.h" #include // For MAXPATHLEN #include @@ -531,7 +532,7 @@ typedef struct { NSTimer *os_timer; unsigned long long id; bool repeats; - double interval; + monotonic_t interval; GLFWuserdatafun callback; void *callback_data; GLFWuserdatafun free_callback_data; @@ -551,7 +552,7 @@ remove_timer_at(size_t idx) { } static void schedule_timer(Timer *t) { - t->os_timer = [NSTimer scheduledTimerWithTimeInterval:t->interval repeats:(t->repeats ? YES: NO) block:^(NSTimer *os_timer) { + t->os_timer = [NSTimer scheduledTimerWithTimeInterval:monotonic_t_to_s_double(t->interval) repeats:(t->repeats ? YES: NO) block:^(NSTimer *os_timer) { for (size_t i = 0; i < num_timers; i++) { if (timers[i].os_timer == os_timer) { timers[i].callback(timers[i].id, timers[i].callback_data); @@ -562,7 +563,7 @@ static void schedule_timer(Timer *t) { }]; } -unsigned long long _glfwPlatformAddTimer(double interval, bool repeats, GLFWuserdatafun callback, void *callback_data, GLFWuserdatafun free_callback) { +unsigned long long _glfwPlatformAddTimer(monotonic_t interval, bool repeats, GLFWuserdatafun callback, void *callback_data, GLFWuserdatafun free_callback) { static unsigned long long timer_counter = 0; if (num_timers >= sizeof(timers)/sizeof(timers[0]) - 1) { _glfwInputError(GLFW_PLATFORM_ERROR, "Too many timers added"); @@ -588,7 +589,7 @@ void _glfwPlatformRemoveTimer(unsigned long long timer_id) { } } -void _glfwPlatformUpdateTimer(unsigned long long timer_id, double interval, bool enabled) { +void _glfwPlatformUpdateTimer(unsigned long long timer_id, monotonic_t interval, bool enabled) { for (size_t i = 0; i < num_timers; i++) { if (timers[i].id == timer_id) { Timer *t = timers + i; diff --git a/glfw/cocoa_platform.h b/glfw/cocoa_platform.h index da6e72bcb..6ca83a7ce 100644 --- a/glfw/cocoa_platform.h +++ b/glfw/cocoa_platform.h @@ -144,7 +144,7 @@ typedef struct _GLFWDisplayLinkNS { CVDisplayLinkRef displayLink; CGDirectDisplayID displayID; - double lastRenderFrameRequestedAt; + monotonic_t lastRenderFrameRequestedAt; } _GLFWDisplayLinkNS; // Cocoa-specific global data diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m index 127354f5f..8445b33cd 100644 --- a/glfw/cocoa_window.m +++ b/glfw/cocoa_window.m @@ -27,6 +27,7 @@ //======================================================================== #include "internal.h" +#include "../kitty/monotonic.h" #include #include @@ -120,7 +121,7 @@ CGDirectDisplayID displayIDForWindow(_GLFWwindow *w) { } static unsigned long long display_link_shutdown_timer = 0; -#define DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL 30 +#define DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL s_to_monotonic_t(30ll) void _glfwShutdownCVDisplayLink(unsigned long long timer_id UNUSED, void *user_data UNUSED) { @@ -147,7 +148,7 @@ requestRenderFrame(_GLFWwindow *w, GLFWcocoarenderframefun callback) { } else { display_link_shutdown_timer = _glfwPlatformAddTimer(DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL, false, _glfwShutdownCVDisplayLink, NULL, NULL); } - double now = glfwGetTime(); + monotonic_t now = glfwGetTime(); for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) { _GLFWDisplayLinkNS *dl = &_glfw.ns.displayLinks.entries[i]; if (dl->displayID == displayID) { @@ -1853,9 +1854,9 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, *yscale = (float) (pixels.size.height / points.size.height); } -double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED) +monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED) { - return [NSEvent doubleClickInterval]; + return s_double_to_monotonic_t([NSEvent doubleClickInterval]); } void _glfwPlatformIconifyWindow(_GLFWwindow* window) diff --git a/glfw/dbus_glfw.c b/glfw/dbus_glfw.c index 2ec4407ab..5213800b8 100644 --- a/glfw/dbus_glfw.c +++ b/glfw/dbus_glfw.c @@ -27,6 +27,7 @@ #include "internal.h" #include "dbus_glfw.h" +#include "../kitty/monotonic.h" #include #include @@ -107,7 +108,7 @@ on_dbus_timer_ready(id_type timer_id UNUSED, void *data) { static dbus_bool_t 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; + monotonic_t interval = ms_to_monotonic_t(dbus_timeout_get_interval(timeout)); if (interval < 0) return FALSE; id_type timer_id = addTimer(dbus_data->eld, data, interval, enabled, true, on_dbus_timer_ready, timeout, NULL); if (!timer_id) return FALSE; diff --git a/glfw/glfw3.h b/glfw/glfw3.h index 9ac6c8f79..f3c70eb38 100644 --- a/glfw/glfw3.h +++ b/glfw/glfw3.h @@ -1707,8 +1707,8 @@ typedef struct GLFWgamepadstate GLFWAPI int glfwInit(void); GLFWAPI void glfwRunMainLoop(GLFWtickcallback callback, void *callback_data); GLFWAPI void glfwStopMainLoop(void); -GLFWAPI unsigned long long glfwAddTimer(double interval, bool repeats, GLFWuserdatafun callback, void * callback_data, GLFWuserdatafun free_callback); -GLFWAPI void glfwUpdateTimer(unsigned long long timer_id, double interval, bool enabled); +GLFWAPI unsigned long long glfwAddTimer(monotonic_t interval, bool repeats, GLFWuserdatafun callback, void * callback_data, GLFWuserdatafun free_callback); +GLFWAPI void glfwUpdateTimer(unsigned long long timer_id, monotonic_t interval, bool enabled); GLFWAPI void glfwRemoveTimer(unsigned long long); /*! @brief Terminates the GLFW library. @@ -3072,7 +3072,7 @@ GLFWAPI void glfwGetWindowContentScale(GLFWwindow* window, float* xscale, float* * * @ingroup window */ -GLFWAPI double glfwGetDoubleClickInterval(GLFWwindow* window); +GLFWAPI monotonic_t glfwGetDoubleClickInterval(GLFWwindow* window); /*! @brief Returns the opacity of the whole window. * @@ -5002,7 +5002,7 @@ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); * * @ingroup input */ -GLFWAPI double glfwGetTime(void); +GLFWAPI monotonic_t glfwGetTime(void); /*! @brief Sets the GLFW timer. * @@ -5029,7 +5029,7 @@ GLFWAPI double glfwGetTime(void); * * @ingroup input */ -GLFWAPI void glfwSetTime(double time); +GLFWAPI void glfwSetTime(monotonic_t time); /*! @brief Returns the current value of the raw timer. * diff --git a/glfw/init.c b/glfw/init.c index 247ee24f5..696d35f1f 100644 --- a/glfw/init.c +++ b/glfw/init.c @@ -201,7 +201,7 @@ _glfwDebug(const char *format, ...) { { va_list vl; - fprintf(stderr, "[%.4f] ", glfwGetTime()); + fprintf(stderr, "[%.4f] ", monotonic_t_to_s_double(glfwGetTime())); va_start(vl, format); vfprintf(stderr, format, vl); va_end(vl); @@ -350,13 +350,13 @@ GLFWAPI void glfwStopMainLoop(void) { } GLFWAPI unsigned long long glfwAddTimer( - double interval, bool repeats, GLFWuserdatafun callback, + monotonic_t interval, bool repeats, GLFWuserdatafun callback, void *callback_data, GLFWuserdatafun free_callback) { return _glfwPlatformAddTimer(interval, repeats, callback, callback_data, free_callback); } -GLFWAPI void glfwUpdateTimer(unsigned long long timer_id, double interval, bool enabled) { +GLFWAPI void glfwUpdateTimer(unsigned long long timer_id, monotonic_t interval, bool enabled) { _glfwPlatformUpdateTimer(timer_id, interval, enabled); } diff --git a/glfw/input.c b/glfw/input.c index 04f005854..87820b57a 100644 --- a/glfw/input.c +++ b/glfw/input.c @@ -28,6 +28,7 @@ //======================================================================== #include "internal.h" +#include "../kitty/monotonic.h" #include #include @@ -1477,25 +1478,23 @@ GLFWAPI const char* glfwGetPrimarySelectionString(GLFWwindow* handle UNUSED) } #endif -GLFWAPI double glfwGetTime(void) +GLFWAPI monotonic_t glfwGetTime(void) { - _GLFW_REQUIRE_INIT_OR_RETURN(0.0); - return (double) (_glfwPlatformGetTimerValue() - _glfw.timer.offset) / - _glfwPlatformGetTimerFrequency(); + _GLFW_REQUIRE_INIT_OR_RETURN(0); + return monotonic(); } -GLFWAPI void glfwSetTime(double time) +GLFWAPI void glfwSetTime(monotonic_t time) { _GLFW_REQUIRE_INIT(); - if (time != time || time < 0.0 || time > 18446744073.0) + if (time < 0) { - _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time); + _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", monotonic_t_to_s_double(time)); return; } - _glfw.timer.offset = _glfwPlatformGetTimerValue() - - (uint64_t) (time * _glfwPlatformGetTimerFrequency()); + // Do nothing } GLFWAPI uint64_t glfwGetTimerValue(void) diff --git a/glfw/internal.h b/glfw/internal.h index 7ac9e3e44..bb54b151c 100644 --- a/glfw/internal.h +++ b/glfw/internal.h @@ -27,6 +27,8 @@ #pragma once +#include "../kitty/monotonic.h" + #if defined(_GLFW_USE_CONFIG_H) #include "glfw_config.h" #endif @@ -687,7 +689,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* right, int* bottom); void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, float* xscale, float* yscale); -double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window); +monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window); void _glfwPlatformIconifyWindow(_GLFWwindow* window); void _glfwPlatformRestoreWindow(_GLFWwindow* window); void _glfwPlatformMaximizeWindow(_GLFWwindow* window); @@ -716,7 +718,7 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, int which, int a, int b, int c, void _glfwPlatformPollEvents(void); void _glfwPlatformWaitEvents(void); -void _glfwPlatformWaitEventsTimeout(double timeout); +void _glfwPlatformWaitEventsTimeout(monotonic_t timeout); void _glfwPlatformPostEmptyEvent(void); void _glfwPlatformGetRequiredInstanceExtensions(char** extensions); @@ -824,8 +826,8 @@ _GLFWwindow* _glfwFocusedWindow(void); _GLFWwindow* _glfwWindowForId(GLFWid id); void _glfwPlatformRunMainLoop(GLFWtickcallback, void*); void _glfwPlatformStopMainLoop(void); -unsigned long long _glfwPlatformAddTimer(double interval, bool repeats, GLFWuserdatafun callback, void *callback_data, GLFWuserdatafun free_callback); -void _glfwPlatformUpdateTimer(unsigned long long timer_id, double interval, bool enabled); +unsigned long long _glfwPlatformAddTimer(monotonic_t interval, bool repeats, GLFWuserdatafun callback, void *callback_data, GLFWuserdatafun free_callback); +void _glfwPlatformUpdateTimer(unsigned long long timer_id, monotonic_t interval, bool enabled); void _glfwPlatformRemoveTimer(unsigned long long timer_id); char* _glfw_strdup(const char* source); diff --git a/glfw/main_loop.h b/glfw/main_loop.h index fdc29691d..a944fd66f 100644 --- a/glfw/main_loop.h +++ b/glfw/main_loop.h @@ -7,6 +7,7 @@ #pragma once #include "internal.h" +#include "../kitty/monotonic.h" #ifndef GLFW_LOOP_BACKEND #define GLFW_LOOP_BACKEND x11 @@ -36,7 +37,7 @@ void _glfwPlatformRunMainLoop(GLFWtickcallback tick_callback, void* data) { EVDBG("main loop exiting"); } -unsigned long long _glfwPlatformAddTimer(double interval, bool repeats, GLFWuserdatafreefun callback, void *callback_data, GLFWuserdatafreefun free_callback) { +unsigned long long _glfwPlatformAddTimer(monotonic_t interval, bool repeats, GLFWuserdatafreefun callback, void *callback_data, GLFWuserdatafreefun free_callback) { return addTimer(&_glfw.GLFW_LOOP_BACKEND.eventLoopData, "user timer", interval, 1, repeats, callback, callback_data, free_callback); } @@ -44,7 +45,7 @@ void _glfwPlatformRemoveTimer(unsigned long long timer_id) { removeTimer(&_glfw.GLFW_LOOP_BACKEND.eventLoopData, timer_id); } -void _glfwPlatformUpdateTimer(unsigned long long timer_id, double interval, bool enabled) { +void _glfwPlatformUpdateTimer(unsigned long long timer_id, monotonic_t interval, bool enabled) { changeTimerInterval(&_glfw.GLFW_LOOP_BACKEND.eventLoopData, timer_id, interval); toggleTimer(&_glfw.GLFW_LOOP_BACKEND.eventLoopData, timer_id, enabled); } diff --git a/glfw/null_window.c b/glfw/null_window.c index c474b0318..c567ca598 100644 --- a/glfw/null_window.c +++ b/glfw/null_window.c @@ -28,6 +28,7 @@ //======================================================================== #include "internal.h" +#include "../kitty/monotonic.h" static int createNativeWindow(_GLFWwindow* window, @@ -150,9 +151,9 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window UNUSED, *yscale = 1.f; } -double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED) +monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED) { - return 0.5; + return ms_to_monotonic_t(500ll); } void _glfwPlatformIconifyWindow(_GLFWwindow* window UNUSED) @@ -257,7 +258,7 @@ void _glfwPlatformWaitEvents(void) { } -void _glfwPlatformWaitEventsTimeout(double timeout UNUSED) +void _glfwPlatformWaitEventsTimeout(monotonic_t timeout UNUSED) { } diff --git a/glfw/window.c b/glfw/window.c index 7d2ba71b9..14d0da95d 100644 --- a/glfw/window.c +++ b/glfw/window.c @@ -29,6 +29,7 @@ //======================================================================== #include "internal.h" +#include "../kitty/monotonic.h" #include #include @@ -738,12 +739,12 @@ GLFWAPI void glfwGetWindowContentScale(GLFWwindow* handle, _glfwPlatformGetWindowContentScale(window, xscale, yscale); } -GLFWAPI double glfwGetDoubleClickInterval(GLFWwindow* handle) +GLFWAPI monotonic_t glfwGetDoubleClickInterval(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; assert(window != NULL); - _GLFW_REQUIRE_INIT_OR_RETURN(0.5f); + _GLFW_REQUIRE_INIT_OR_RETURN(ms_to_monotonic_t(500ll)); return _glfwPlatformGetDoubleClickInterval(window); } diff --git a/glfw/wl_init.c b/glfw/wl_init.c index 396972b5c..e9d1312a8 100644 --- a/glfw/wl_init.c +++ b/glfw/wl_init.c @@ -29,6 +29,7 @@ #define _GNU_SOURCE #include "internal.h" #include "backend_utils.h" +#include "../kitty/monotonic.h" #include #include @@ -403,7 +404,7 @@ static void dispatchPendingKeyRepeats(id_type timer_id UNUSED, void *data UNUSED) { if (_glfw.wl.keyRepeatInfo.keyboardFocus != _glfw.wl.keyboardFocus || _glfw.wl.keyboardRepeatRate == 0) return; glfw_xkb_handle_key_event(_glfw.wl.keyRepeatInfo.keyboardFocus, &_glfw.wl.xkb, _glfw.wl.keyRepeatInfo.key, GLFW_REPEAT); - changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, (1.0 / (double)_glfw.wl.keyboardRepeatRate)); + changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, (s_to_monotonic_t(1ll) / (monotonic_t)_glfw.wl.keyboardRepeatRate)); toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 1); } @@ -429,7 +430,7 @@ static void keyboardHandleKey(void* data UNUSED, _glfw.wl.keyRepeatInfo.keyboardFocus = window; } if (repeatable) { - changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, (double)(_glfw.wl.keyboardRepeatDelay) / 1000.0); + changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, _glfw.wl.keyboardRepeatDelay); } toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, repeatable ? 1 : 0); } @@ -454,7 +455,7 @@ static void keyboardHandleRepeatInfo(void* data UNUSED, return; _glfw.wl.keyboardRepeatRate = rate; - _glfw.wl.keyboardRepeatDelay = delay; + _glfw.wl.keyboardRepeatDelay = ms_to_monotonic_t(delay); } static const struct wl_keyboard_listener keyboardListener = { @@ -728,8 +729,8 @@ int _glfwPlatformInit(void) "Wayland: Failed to initialize event loop data"); } glfw_dbus_init(&_glfw.wl.dbus, &_glfw.wl.eventLoopData); - _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.keyRepeatInfo.keyRepeatTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-key-repeat", ms_to_monotonic_t(500ll), 0, true, dispatchPendingKeyRepeats, NULL, NULL); + _glfw.wl.cursorAnimationTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-cursor-animation", ms_to_monotonic_t(500ll), 0, true, animateCursorImage, NULL, NULL); _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 26f5bd8e8..2d978c2b7 100644 --- a/glfw/wl_platform.h +++ b/glfw/wl_platform.h @@ -250,7 +250,7 @@ typedef struct _GLFWlibraryWayland uint32_t pointerSerial; int32_t keyboardRepeatRate; - int32_t keyboardRepeatDelay; + monotonic_t keyboardRepeatDelay; struct { uint32_t key; id_type keyRepeatTimer; diff --git a/glfw/wl_window.c b/glfw/wl_window.c index 35c6e3c60..d6b9fce03 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -32,6 +32,7 @@ #include "backend_utils.h" #include "memfd.h" #include "linux_notify.h" +#include "../kitty/monotonic.h" #include #include @@ -684,7 +685,7 @@ setCursorImage(_GLFWcursorWayland* cursorWayland) image = cursorWayland->cursor->images[cursorWayland->currentImage]; buffer = wl_cursor_image_get_buffer(image); if (image->delay) { - changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, ((double)image->delay) / 1000.0); + changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, ms_to_monotonic_t(image->delay)); toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 1); } else { toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 0); @@ -745,11 +746,11 @@ abortOnFatalError(int last_error) { } static void -handleEvents(double timeout) +handleEvents(monotonic_t timeout) { struct wl_display* display = _glfw.wl.display; errno = 0; - EVDBG("starting handleEvents(%.2f)", timeout); + EVDBG("starting handleEvents(%.2f)", monotonic_t_to_s_double(timeout)); while (wl_display_prepare_read(display) != 0) { while(1) { @@ -1052,9 +1053,9 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window, *yscale = (float) window->wl.scale; } -double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED) +monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED) { - return 0.5; + return ms_to_monotonic_t(500ll); } void _glfwPlatformIconifyWindow(_GLFWwindow* window) @@ -1227,11 +1228,11 @@ void _glfwPlatformPollEvents(void) void _glfwPlatformWaitEvents(void) { - double timeout = wl_display_dispatch_pending(_glfw.wl.display) > 0 ? 0 : -1; + monotonic_t timeout = wl_display_dispatch_pending(_glfw.wl.display) > 0 ? 0 : -1; handleEvents(timeout); } -void _glfwPlatformWaitEventsTimeout(double timeout) +void _glfwPlatformWaitEventsTimeout(monotonic_t timeout) { if (wl_display_dispatch_pending(_glfw.wl.display) > 0) timeout = 0; handleEvents(timeout); @@ -1462,8 +1463,8 @@ static void send_text(char *text, int fd) { if (text) { size_t len = strlen(text), pos = 0; - double start = glfwGetTime(); - while (pos < len && glfwGetTime() - start < 2.0) { + monotonic_t start = glfwGetTime(); + while (pos < len && glfwGetTime() - start < s_to_monotonic_t(2ll)) { ssize_t ret = write(fd, text + pos, len - pos); if (ret < 0) { if (errno == EAGAIN || errno == EINTR) continue; @@ -1496,7 +1497,7 @@ static char* read_offer_string(int data_pipe) { struct pollfd fds; fds.fd = data_pipe; fds.events = POLLIN; - double start = glfwGetTime(); + monotonic_t start = glfwGetTime(); #define bail(...) { \ _glfwInputError(GLFW_PLATFORM_ERROR, __VA_ARGS__); \ free(buf); buf = NULL; \ @@ -1504,7 +1505,7 @@ static char* read_offer_string(int data_pipe) { return NULL; \ } - while (glfwGetTime() - start < 2) { + while (glfwGetTime() - start < s_to_monotonic_t(2ll)) { int ret = poll(&fds, 1, 2000); if (ret == -1) { if (errno == EINTR) continue; diff --git a/glfw/x11_window.c b/glfw/x11_window.c index 26a17de62..71c8fc003 100644 --- a/glfw/x11_window.c +++ b/glfw/x11_window.c @@ -31,6 +31,7 @@ #include "internal.h" #include "backend_utils.h" #include "linux_notify.h" +#include "../kitty/monotonic.h" #include #include @@ -61,8 +62,8 @@ static unsigned _glfwDispatchX11Events(void); static void -handleEvents(double timeout) { - EVDBG("starting handleEvents(%.2f)", timeout); +handleEvents(monotonic_t timeout) { + EVDBG("starting handleEvents(%.2f)", monotonic_t_to_s_double(timeout)); int display_read_ok = pollForEvents(&_glfw.x11.eventLoopData, timeout); EVDBG("display_read_ok: %d", display_read_ok); if (display_read_ok) { @@ -77,9 +78,9 @@ handleEvents(double timeout) { } static bool -waitForX11Event(double timeout) { +waitForX11Event(monotonic_t timeout) { // returns true if there is X11 data waiting to be read, does not run watches and timers - double end_time = glfwGetTime() + timeout; + monotonic_t end_time = glfwGetTime() + timeout; while(true) { if (timeout >= 0) { const int result = pollWithTimeout(_glfw.x11.eventLoopData.fds, 1, timeout); @@ -109,7 +110,7 @@ static bool waitForVisibilityNotify(_GLFWwindow* window) VisibilityNotify, &dummy)) { - if (!waitForX11Event(0.1)) + if (!waitForX11Event(ms_to_monotonic_t(100ll))) return false; } @@ -880,7 +881,7 @@ static const char* getSelectionString(Atom selection) Atom actualType; int actualFormat; unsigned long itemCount, bytesAfter; - double start = glfwGetTime(); + monotonic_t start = glfwGetTime(); XEvent notification, dummy; XConvertSelection(_glfw.x11.display, @@ -895,10 +896,10 @@ static const char* getSelectionString(Atom selection) SelectionNotify, ¬ification)) { - double time = glfwGetTime(); - if (time - start > 2) + monotonic_t time = glfwGetTime(); + if (time - start > 2ll) return ""; - waitForX11Event(2.0 - (time - start)); + waitForX11Event(s_to_monotonic_t(2ll) - (time - start)); } if (notification.xselection.property == None) @@ -935,10 +936,10 @@ static const char* getSelectionString(Atom selection) isSelPropNewValueNotify, (XPointer) ¬ification)) { - double time = glfwGetTime(); - if (time - start > 2) + monotonic_t time = glfwGetTime(); + if (time - start > s_to_monotonic_t(2ll)) return ""; - waitForX11Event(2.0 - (time - start)); + waitForX11Event(s_to_monotonic_t(2ll) - (time - start)); } XFree(data); @@ -2066,7 +2067,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, isFrameExtentsEvent, (XPointer) window)) { - if (!waitForX11Event(0.5)) + if (!waitForX11Event(ms_to_monotonic_t(500ll))) { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue"); @@ -2103,9 +2104,9 @@ void _glfwPlatformGetWindowContentScale(_GLFWwindow* window UNUSED, *yscale = _glfw.x11.contentScaleY; } -double _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED) +monotonic_t _glfwPlatformGetDoubleClickInterval(_GLFWwindow* window UNUSED) { - return 0.5; + return ms_to_monotonic_t(500ll); } void _glfwPlatformIconifyWindow(_GLFWwindow* window) @@ -2527,11 +2528,11 @@ void _glfwPlatformPollEvents(void) void _glfwPlatformWaitEvents(void) { - double timeout = _glfwDispatchX11Events() ? 0 : -1; + monotonic_t timeout = _glfwDispatchX11Events() ? 0 : -1; handleEvents(timeout); } -void _glfwPlatformWaitEventsTimeout(double timeout) +void _glfwPlatformWaitEventsTimeout(monotonic_t timeout) { if (_glfwDispatchX11Events()) timeout = 0; handleEvents(timeout); diff --git a/kitty/child-monitor.c b/kitty/child-monitor.c index aafc76277..89ca8d92c 100644 --- a/kitty/child-monitor.c +++ b/kitty/child-monitor.c @@ -11,6 +11,7 @@ #include "screen.h" #include "fonts.h" #include "charsets.h" +#include "monotonic.h" #include #include #include @@ -34,7 +35,7 @@ extern PyTypeObject Screen_Type; #endif #define USE_RENDER_FRAMES (global_state.has_render_frames && OPT(sync_to_monitor)) -static void (*parse_func)(Screen*, PyObject*, double); +static void (*parse_func)(Screen*, PyObject*, monotonic_t); typedef struct { char *data; @@ -110,10 +111,10 @@ static size_t reaped_pids_count = 0; // The max time (in secs) to wait for events from the window system // before ticking over the main loop. Negative values mean wait forever. -static double maximum_wait = -1.0; +static monotonic_t maximum_wait = -1; static inline void -set_maximum_wait(double val) { +set_maximum_wait(monotonic_t val) { if (val >= 0 && (val < maximum_wait || maximum_wait < 0)) maximum_wait = val; } @@ -296,11 +297,11 @@ shutdown_monitor(ChildMonitor *self, PyObject *a UNUSED) { } static inline bool -do_parse(ChildMonitor *self, Screen *screen, double now) { +do_parse(ChildMonitor *self, Screen *screen, monotonic_t now) { bool input_read = false; screen_mutex(lock, read); if (screen->read_buf_sz || screen->pending_mode.used) { - double time_since_new_input = now - screen->new_input_at; + monotonic_t time_since_new_input = now - screen->new_input_at; if (time_since_new_input >= OPT(input_delay)) { bool read_buf_full = screen->read_buf_sz >= READ_BUF_SZ; input_read = true; @@ -308,7 +309,7 @@ do_parse(ChildMonitor *self, Screen *screen, double now) { if (read_buf_full) wakeup_io_loop(self, false); // Ensure the read fd has POLLIN set screen->new_input_at = 0; if (screen->pending_mode.activated_at) { - double time_since_pending = MAX(0, now - screen->pending_mode.activated_at); + monotonic_t time_since_pending = MAX(0, now - screen->pending_mode.activated_at); set_maximum_wait(screen->pending_mode.wait_time - time_since_pending); } } else set_maximum_wait(OPT(input_delay) - time_since_new_input); @@ -322,7 +323,7 @@ parse_input(ChildMonitor *self) { // Parse all available input that was read in the I/O thread. size_t count = 0, remove_count = 0; bool input_read = false; - double now = monotonic(); + monotonic_t now = monotonic(); PyObject *msg = NULL; children_mutex(lock); while (remove_queue_count) { @@ -485,22 +486,22 @@ pyset_iutf8(ChildMonitor *self, PyObject *args) { extern void cocoa_update_menu_bar_title(PyObject*); static inline void -collect_cursor_info(CursorRenderInfo *ans, Window *w, double now, OSWindow *os_window) { +collect_cursor_info(CursorRenderInfo *ans, Window *w, monotonic_t now, OSWindow *os_window) { ScreenRenderData *rd = &w->render_data; Cursor *cursor = rd->screen->cursor; ans->x = cursor->x; ans->y = cursor->y; ans->is_visible = false; if (rd->screen->scrolled_by || !screen_is_cursor_visible(rd->screen)) return; - double time_since_start_blink = now - os_window->cursor_blink_zero_time; + monotonic_t time_since_start_blink = now - os_window->cursor_blink_zero_time; bool cursor_blinking = OPT(cursor_blink_interval) > 0 && os_window->is_focused && (OPT(cursor_stop_blinking_after) == 0 || time_since_start_blink <= OPT(cursor_stop_blinking_after)); bool do_draw_cursor = true; if (cursor_blinking) { - int t = (int)(time_since_start_blink * 1000); - int d = (int)(OPT(cursor_blink_interval) * 1000); + int t = monotonic_t_to_ms(time_since_start_blink); + int d = monotonic_t_to_ms(OPT(cursor_blink_interval)); int n = t / d; do_draw_cursor = n % 2 == 0 ? true : false; - double bucket = (n + 1) * d; - double delay = (bucket / 1000.0) - time_since_start_blink; + monotonic_t bucket = ms_to_monotonic_t((n + 1) * d); + monotonic_t delay = bucket - time_since_start_blink; set_maximum_wait(delay); } if (!do_draw_cursor) { ans->is_visible = false; return; } @@ -526,7 +527,7 @@ update_window_title(Window *w, OSWindow *os_window) { } static inline bool -prepare_to_render_os_window(OSWindow *os_window, double now, unsigned int *active_window_id, color_type *active_window_bg, unsigned int *num_visible_windows, bool *all_windows_have_same_bg) { +prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int *active_window_id, color_type *active_window_bg, unsigned int *num_visible_windows, bool *all_windows_have_same_bg) { #define TD os_window->tab_bar_render_data bool needs_render = os_window->needs_render; os_window->needs_render = false; @@ -555,10 +556,10 @@ prepare_to_render_os_window(OSWindow *os_window, double now, unsigned int *activ if (*num_visible_windows == 1) first_window_bg = window_bg; if (first_window_bg != window_bg) all_windows_have_same_bg = false; if (w->last_drag_scroll_at > 0) { - if (now - w->last_drag_scroll_at >= 0.02) { + if (now - w->last_drag_scroll_at >= ms_to_monotonic_t(20ll)) { if (drag_scroll(w, os_window)) { w->last_drag_scroll_at = now; - set_maximum_wait(0.02); + set_maximum_wait(ms_to_monotonic_t(20ll)); needs_render = true; } else w->last_drag_scroll_at = 0; } else set_maximum_wait(now - w->last_drag_scroll_at); @@ -579,7 +580,7 @@ prepare_to_render_os_window(OSWindow *os_window, double now, unsigned int *activ } static inline void -render_os_window(OSWindow *os_window, double now, unsigned int active_window_id, color_type active_window_bg, unsigned int num_visible_windows, bool all_windows_have_same_bg) { +render_os_window(OSWindow *os_window, monotonic_t now, unsigned int active_window_id, color_type active_window_bg, unsigned int num_visible_windows, bool all_windows_have_same_bg) { // ensure all pixels are cleared to background color at least once in every buffer if (os_window->clear_count++ < 3) blank_os_window(os_window); Tab *tab = os_window->tabs + os_window->active_tab; @@ -601,7 +602,7 @@ render_os_window(OSWindow *os_window, double now, unsigned int active_window_id, bool is_active_window = i == tab->active_window; draw_cells(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx * x_ratio, WD.dy * y_ratio, WD.screen, os_window, is_active_window, true); if (WD.screen->start_visual_bell_at != 0) { - double bell_left = OPT(visual_bell_duration) - (now - WD.screen->start_visual_bell_at); + monotonic_t bell_left = OPT(visual_bell_duration) - (now - WD.screen->start_visual_bell_at); set_maximum_wait(bell_left); } w->cursor_visible_at_last_render = WD.screen->cursor_render_info.is_visible; w->last_cursor_x = WD.screen->cursor_render_info.x; w->last_cursor_y = WD.screen->cursor_render_info.y; w->last_cursor_shape = WD.screen->cursor_render_info.shape; @@ -638,17 +639,17 @@ draw_resizing_text(OSWindow *w) { } static inline bool -no_render_frame_received_recently(OSWindow *w, double now, double max_wait) { +no_render_frame_received_recently(OSWindow *w, monotonic_t now, monotonic_t max_wait) { bool ans = now - w->last_render_frame_received_at > max_wait; - if (ans) log_error("No render frame received in %f seconds, re-requesting at: %f", max_wait, now); + if (ans) log_error("No render frame received in %f seconds, re-requesting at: %f", monotonic_t_to_s_double(max_wait), monotonic_t_to_s_double(now)); return ans; } static inline void -render(double now, bool input_read) { +render(monotonic_t now, bool input_read) { EVDBG("input_read: %d", input_read); - static double last_render_at = -DBL_MAX; - double time_since_last_render = now - last_render_at; + static monotonic_t last_render_at = MONOTONIC_T_MIN; + monotonic_t time_since_last_render = now - last_render_at; if (!input_read && time_since_last_render < OPT(repaint_delay)) { set_maximum_wait(OPT(repaint_delay) - time_since_last_render); return; @@ -662,7 +663,7 @@ render(double now, bool input_read) { continue; } if (USE_RENDER_FRAMES && w->render_state != RENDER_FRAME_READY) { - if (w->render_state == RENDER_FRAME_NOT_REQUESTED || no_render_frame_received_recently(w, now, 0.25)) request_frame_render(w); + if (w->render_state == RENDER_FRAME_NOT_REQUESTED || no_render_frame_received_recently(w, now, ms_to_monotonic_t(250ll))) request_frame_render(w); continue; } make_os_window_context_current(w); @@ -806,7 +807,7 @@ add_python_timer(PyObject *self UNUSED, PyObject *args) { double interval; int repeats = 1; if (!PyArg_ParseTuple(args, "Od|p", &callback, &interval, &repeats)) return NULL; - unsigned long long timer_id = add_main_loop_timer(interval, repeats ? true: false, python_timer_callback, callback, python_timer_cleanup); + unsigned long long timer_id = add_main_loop_timer(s_double_to_monotonic_t(interval), repeats ? true: false, python_timer_callback, callback, python_timer_cleanup); Py_INCREF(callback); return Py_BuildValue("K", timer_id); } @@ -821,7 +822,7 @@ remove_python_timer(PyObject *self UNUSED, PyObject *args) { static inline void -process_pending_resizes(double now) { +process_pending_resizes(monotonic_t now) { global_state.has_pending_resizes = false; for (size_t i = 0; i < global_state.num_os_windows; i++) { OSWindow *w = global_state.os_windows + i; @@ -830,11 +831,11 @@ process_pending_resizes(double now) { if (w->live_resize.from_os_notification) { if (w->live_resize.os_says_resize_complete || (now - w->live_resize.last_resize_event_at) > 1) update_viewport = true; } else { - double debounce_time = OPT(resize_debounce_time); + monotonic_t debounce_time = OPT(resize_debounce_time); // if more than one resize event has occurred, wait at least 0.2 secs // before repainting, to avoid rapid transitions between the cells banner // and the normal screen - if (w->live_resize.num_of_resize_events > 1 && OPT(resize_draw_strategy) == RESIZE_DRAW_SIZE) debounce_time = MAX(0.2, debounce_time); + if (w->live_resize.num_of_resize_events > 1 && OPT(resize_draw_strategy) == RESIZE_DRAW_SIZE) debounce_time = MAX(ms_to_monotonic_t(200ll), debounce_time); if (now - w->live_resize.last_resize_event_at >= debounce_time) update_viewport = true; else { global_state.has_pending_resizes = true; @@ -916,7 +917,7 @@ process_global_state(void *data) { maximum_wait = -1; bool state_check_timer_enabled = false; - double now = monotonic(); + monotonic_t now = monotonic(); if (global_state.has_pending_resizes) process_pending_resizes(now); bool input_read = parse_input(self); render(now, input_read); @@ -1167,7 +1168,7 @@ io_loop(void *data) { size_t i; int ret; bool has_more, data_received, has_pending_wakeups = false; - double last_main_loop_wakeup_at = -1, now = -1; + monotonic_t last_main_loop_wakeup_at = -1, now = -1; Screen *screen; ChildMonitor *self = (ChildMonitor*)data; set_thread_name("KittyChildMon"); @@ -1188,8 +1189,8 @@ io_loop(void *data) { } if (has_pending_wakeups) { now = monotonic(); - double time_delta = OPT(input_delay) - (now - last_main_loop_wakeup_at); - if (time_delta >= 0) ret = poll(fds, self->count + EXTRA_FDS, (int)ceil(1000 * time_delta)); + monotonic_t time_delta = OPT(input_delay) - (now - last_main_loop_wakeup_at); + if (time_delta >= 0) ret = poll(fds, self->count + EXTRA_FDS, monotonic_t_to_ms(time_delta)); else ret = 0; } else { ret = poll(fds, self->count + EXTRA_FDS, -1); diff --git a/kitty/cocoa_window.m b/kitty/cocoa_window.m index f404173f7..a121536bd 100644 --- a/kitty/cocoa_window.m +++ b/kitty/cocoa_window.m @@ -7,6 +7,7 @@ #include "state.h" +#include "monotonic.h" #include #include @@ -411,7 +412,7 @@ cocoa_get_lang(PyObject UNUSED *self) { } // autoreleasepool } -double +monotonic_t cocoa_cursor_blink_interval(void) { @autoreleasepool { @@ -425,7 +426,7 @@ cocoa_cursor_blink_interval(void) { } else if (period_ms) { ans = period_ms; } - return ans > max_value ? 0.0 : ans; + return ans > max_value ? 0ll : ms_double_to_monotonic_t(ans); } // autoreleasepool } diff --git a/kitty/data-types.c b/kitty/data-types.c index 26f7d7041..72d38fad0 100644 --- a/kitty/data-types.c +++ b/kitty/data-types.c @@ -22,31 +22,10 @@ #ifdef WITH_PROFILER #include #endif - -/* To millisecond (10^-3) */ -#define SEC_TO_MS 1000 - -/* To microseconds (10^-6) */ -#define MS_TO_US 1000 -#define SEC_TO_US (SEC_TO_MS * MS_TO_US) - -/* To nanoseconds (10^-9) */ -#define US_TO_NS 1000 -#define MS_TO_NS (MS_TO_US * US_TO_NS) -#define SEC_TO_NS (SEC_TO_MS * MS_TO_NS) - -/* Conversion from nanoseconds */ -#define NS_TO_MS (1000 * 1000) -#define NS_TO_US (1000) +#include "monotonic.h" #ifdef __APPLE__ #include -#include -static mach_timebase_info_data_t timebase = {0}; - -static inline double monotonic_(void) { - return ((double)(mach_absolute_time() * timebase.numer) / timebase.denom)/SEC_TO_NS; -} static PyObject* user_cache_dir() { @@ -73,25 +52,7 @@ process_group_map() { free(buf); return ans; } - -#else -#include -static inline double monotonic_(void) { - struct timespec ts = {0}; -#ifdef CLOCK_HIGHRES - clock_gettime(CLOCK_HIGHRES, &ts); -#elif CLOCK_MONOTONIC_RAW - clock_gettime(CLOCK_MONOTONIC_RAW, &ts); -#else - clock_gettime(CLOCK_MONOTONIC, &ts); #endif - return (((double)ts.tv_nsec) / SEC_TO_NS) + (double)ts.tv_sec; -} -#endif - -static double start_time = 0; - -double monotonic() { return monotonic_() - start_time; } static PyObject* redirect_std_streams(PyObject UNUSED *self, PyObject *args) { @@ -254,9 +215,8 @@ PyInit_fast_data_types(void) { m = PyModule_Create(&module); if (m == NULL) return NULL; #ifdef __APPLE__ - mach_timebase_info(&timebase); #endif - start_time = monotonic_(); + init_monotonic(); if (m != NULL) { if (!init_logging(m)) return NULL; diff --git a/kitty/data-types.h b/kitty/data-types.h index f1a52180c..1dc24980a 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -292,7 +292,6 @@ void apply_sgr_to_cells(GPUCell *first_cell, unsigned int cell_count, unsigned i const char* cell_as_sgr(const GPUCell *, const GPUCell *); const char* cursor_as_sgr(const Cursor *); -double monotonic(void); PyObject* cm_thread_write(PyObject *self, PyObject *args); bool schedule_write_to_child(unsigned long id, unsigned int num, ...); bool set_iutf8(int, bool); diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index 65b8d2cde..9529feada 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -7,6 +7,7 @@ #pragma once #include #include +#include "../kitty/monotonic.h" @@ -1487,11 +1488,11 @@ typedef void (*glfwStopMainLoop_func)(void); glfwStopMainLoop_func glfwStopMainLoop_impl; #define glfwStopMainLoop glfwStopMainLoop_impl -typedef unsigned long long (*glfwAddTimer_func)(double, bool, GLFWuserdatafun, void *, GLFWuserdatafun); +typedef unsigned long long (*glfwAddTimer_func)(monotonic_t, bool, GLFWuserdatafun, void *, GLFWuserdatafun); glfwAddTimer_func glfwAddTimer_impl; #define glfwAddTimer glfwAddTimer_impl -typedef void (*glfwUpdateTimer_func)(unsigned long long, double, bool); +typedef void (*glfwUpdateTimer_func)(unsigned long long, monotonic_t, bool); glfwUpdateTimer_func glfwUpdateTimer_impl; #define glfwUpdateTimer glfwUpdateTimer_impl @@ -1659,7 +1660,7 @@ typedef void (*glfwGetWindowContentScale_func)(GLFWwindow*, float*, float*); glfwGetWindowContentScale_func glfwGetWindowContentScale_impl; #define glfwGetWindowContentScale glfwGetWindowContentScale_impl -typedef double (*glfwGetDoubleClickInterval_func)(GLFWwindow*); +typedef monotonic_t (*glfwGetDoubleClickInterval_func)(GLFWwindow*); glfwGetDoubleClickInterval_func glfwGetDoubleClickInterval_impl; #define glfwGetDoubleClickInterval glfwGetDoubleClickInterval_impl @@ -1911,11 +1912,11 @@ typedef const char* (*glfwGetClipboardString_func)(GLFWwindow*); glfwGetClipboardString_func glfwGetClipboardString_impl; #define glfwGetClipboardString glfwGetClipboardString_impl -typedef double (*glfwGetTime_func)(void); +typedef monotonic_t (*glfwGetTime_func)(void); glfwGetTime_func glfwGetTime_impl; #define glfwGetTime glfwGetTime_impl -typedef void (*glfwSetTime_func)(double); +typedef void (*glfwSetTime_func)(monotonic_t); glfwSetTime_func glfwSetTime_impl; #define glfwSetTime glfwSetTime_impl diff --git a/kitty/glfw.c b/kitty/glfw.c index a4aa45668..641075ee6 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -7,6 +7,7 @@ #include "state.h" #include "glfw_tests.h" #include "fonts.h" +#include "monotonic.h" #include #include "glfw-wrapper.h" extern bool cocoa_make_window_resizable(void *w, bool); @@ -17,7 +18,7 @@ extern void cocoa_set_activation_policy(bool); extern void cocoa_set_titlebar_color(void *w, color_type color); extern bool cocoa_alt_option_key_pressed(unsigned long); extern size_t cocoa_get_workspace_ids(void *w, size_t *workspace_ids, size_t array_sz); -extern double cocoa_cursor_blink_interval(void); +extern monotonic_t cocoa_cursor_blink_interval(void); #if GLFW_KEY_LAST >= MAX_KEY_COUNT @@ -83,7 +84,7 @@ log_event(const char *format, ...) { { va_list vl; - fprintf(stderr, "[%.4f] ", glfwGetTime()); + fprintf(stderr, "[%.4f] ", monotonic_t_to_s_double(glfwGetTime())); va_start(vl, format); vfprintf(stderr, format, vl); va_end(vl); @@ -248,7 +249,7 @@ cursor_enter_callback(GLFWwindow *w, int entered) { if (!set_callback_window(w)) return; if (entered) { show_mouse_cursor(w); - double now = monotonic(); + monotonic_t now = monotonic(); global_state.callback_os_window->last_mouse_activity_at = now; if (is_window_ready_for_callbacks()) enter_event(); request_tick_callback(); @@ -261,7 +262,7 @@ mouse_button_callback(GLFWwindow *w, int button, int action, int mods) { if (!set_callback_window(w)) return; show_mouse_cursor(w); mods_at_last_key_or_button_event = mods; - double now = monotonic(); + monotonic_t now = monotonic(); global_state.callback_os_window->last_mouse_activity_at = now; if (button >= 0 && (unsigned int)button < arraysz(global_state.callback_os_window->mouse_button_pressed)) { global_state.callback_os_window->mouse_button_pressed[button] = action == GLFW_PRESS ? true : false; @@ -275,7 +276,7 @@ static void cursor_pos_callback(GLFWwindow *w, double x, double y) { if (!set_callback_window(w)) return; show_mouse_cursor(w); - double now = monotonic(); + monotonic_t now = monotonic(); global_state.callback_os_window->last_mouse_activity_at = now; global_state.callback_os_window->cursor_blink_zero_time = now; global_state.callback_os_window->mouse_x = x * global_state.callback_os_window->viewport_x_ratio; @@ -289,7 +290,7 @@ static void scroll_callback(GLFWwindow *w, double xoffset, double yoffset, int flags) { if (!set_callback_window(w)) return; show_mouse_cursor(w); - double now = monotonic(); + monotonic_t now = monotonic(); global_state.callback_os_window->last_mouse_activity_at = now; if (is_window_ready_for_callbacks()) scroll_event(xoffset, yoffset, flags); request_tick_callback(); @@ -308,7 +309,7 @@ window_focus_callback(GLFWwindow *w, int focused) { focus_in_event(); global_state.callback_os_window->last_focused_counter = ++focus_counter; } - double now = monotonic(); + monotonic_t now = monotonic(); global_state.callback_os_window->last_mouse_activity_at = now; global_state.callback_os_window->cursor_blink_zero_time = now; if (is_window_ready_for_callbacks()) { @@ -602,10 +603,10 @@ create_os_window(PyObject UNUSED *self, PyObject *args) { #undef CC if (OPT(click_interval) < 0) OPT(click_interval) = glfwGetDoubleClickInterval(glfw_window); if (OPT(cursor_blink_interval) < 0) { - OPT(cursor_blink_interval) = 0.5; + OPT(cursor_blink_interval) = ms_to_monotonic_t(500ll); #ifdef __APPLE__ - double cbi = cocoa_cursor_blink_interval(); - if (cbi >= 0) OPT(cursor_blink_interval) = cbi / 2000.0; + monotonic_t cbi = cocoa_cursor_blink_interval(); + if (cbi >= 0) OPT(cursor_blink_interval) = cbi / 2; #endif } is_first_window = false; @@ -655,7 +656,7 @@ create_os_window(PyObject UNUSED *self, PyObject *args) { cocoa_make_window_resizable(glfwGetCocoaWindow(glfw_window), OPT(macos_window_resizable)); } else log_error("Failed to load glfwGetCocoaWindow"); #endif - double now = monotonic(); + monotonic_t now = monotonic(); w->is_focused = true; w->cursor_blink_zero_time = now; w->last_mouse_activity_at = now; @@ -854,9 +855,9 @@ get_clipboard_string(PYNOARG) { void ring_audio_bell(OSWindow *w UNUSED) { - static double last_bell_at = -1; - double now = monotonic(); - if (now - last_bell_at <= 0.1) return; + static monotonic_t last_bell_at = -1; + monotonic_t now = monotonic(); + if (now - last_bell_at <= ms_to_monotonic_t(100ll)) return; last_bell_at = now; #ifdef __APPLE__ if (w->handle) { @@ -1139,12 +1140,12 @@ 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) { +add_main_loop_timer(monotonic_t 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 -update_main_loop_timer(id_type timer_id, double interval, bool enabled) { +update_main_loop_timer(id_type timer_id, monotonic_t interval, bool enabled) { glfwUpdateTimer(timer_id, interval, enabled); } diff --git a/kitty/graphics.c b/kitty/graphics.c index e70fdee82..f306b8ef0 100644 --- a/kitty/graphics.c +++ b/kitty/graphics.c @@ -121,7 +121,7 @@ trim_predicate(Image *img) { static int oldest_last(const void* a, const void *b) { - double ans = ((Image*)(b))->atime - ((Image*)(a))->atime; + monotonic_t ans = ((Image*)(b))->atime - ((Image*)(a))->atime; return ans < 0 ? -1 : (ans == 0 ? 0 : 1); } diff --git a/kitty/graphics.h b/kitty/graphics.h index 4f9e5a56e..3a85dbc65 100644 --- a/kitty/graphics.h +++ b/kitty/graphics.h @@ -6,6 +6,7 @@ #pragma once #include "data-types.h" +#include "monotonic.h" typedef struct { unsigned char action, transmission_type, compressed, delete_action; @@ -50,7 +51,7 @@ typedef struct { ImageRef *refs; size_t refcnt, refcap; - double atime; + monotonic_t atime; size_t used_storage; } Image; diff --git a/kitty/kittens.c b/kitty/kittens.c index 28c0e74e0..0596d13de 100644 --- a/kitty/kittens.c +++ b/kitty/kittens.c @@ -6,6 +6,7 @@ */ #include "data-types.h" +#include "monotonic.h" #define CMD_BUF_SZ 2048 @@ -34,13 +35,13 @@ add_char(char buf[CMD_BUF_SZ], size_t *pos, char ch, PyObject *ans) { } static inline bool -read_response(int fd, double timeout, PyObject *ans) { +read_response(int fd, monotonic_t timeout, PyObject *ans) { static char buf[CMD_BUF_SZ]; size_t pos = 0; enum ReadState {START, STARTING_ESC, P, AT, K, I, T, T2, Y, HYPHEN, C, M, BODY, TRAILING_ESC}; enum ReadState state = START; char ch; - double end_time = monotonic() + timeout; + monotonic_t end_time = monotonic() + timeout; while(monotonic() <= end_time) { ssize_t len = read(fd, &ch, 1); if (len == 0) continue; @@ -94,7 +95,7 @@ read_command_response(PyObject *self UNUSED, PyObject *args) { int fd; PyObject *ans; if (!PyArg_ParseTuple(args, "idO!", &fd, &timeout, &PyList_Type, &ans)) return NULL; - if (!read_response(fd, timeout, ans)) return NULL; + if (!read_response(fd, s_double_to_monotonic_t(timeout), ans)) return NULL; Py_RETURN_NONE; } diff --git a/kitty/monotonic.h b/kitty/monotonic.h new file mode 100644 index 000000000..b25677c0b --- /dev/null +++ b/kitty/monotonic.h @@ -0,0 +1,84 @@ +/* + * monotonic.h + * Copyright (C) 2019 Kovid Goyal + * + * Distributed under terms of the GPL3 license. + */ + +#pragma once + + +#include +#include + +#define MONOTONIC_T_MAX INT64_MAX +#define MONOTONIC_T_MIN INT64_MIN + +typedef int64_t monotonic_t; + +static inline monotonic_t calc_nano_time(struct timespec time) { + int64_t result = (monotonic_t)time.tv_sec; + result *= 1000LL; + result *= 1000LL; + result *= 1000LL; + result += (monotonic_t)time.tv_nsec; + return result; +} + +static inline struct timespec calc_time(monotonic_t nsec) { + struct timespec result; + result.tv_sec = nsec / (1000LL * 1000LL * 1000LL); + result.tv_nsec = nsec % (1000LL * 1000LL * 1000LL); + return result; +} + +static inline monotonic_t s_double_to_monotonic_t(double time) { + time *= 1000.0; + time *= 1000.0; + time *= 1000.0; + return (monotonic_t)time; +} + +static inline monotonic_t ms_double_to_monotonic_t(double time) { + time *= 1000.0; + time *= 1000.0; + return (monotonic_t)time; +} + +static inline monotonic_t s_to_monotonic_t(monotonic_t time) { + return time * 1000ll * 1000ll * 1000ll; +} + +static inline monotonic_t ms_to_monotonic_t(monotonic_t time) { + return time * 1000ll * 1000ll; +} + +static inline int monotonic_t_to_ms(monotonic_t time) { + return time / 1000ll / 1000ll; +} + +static inline double monotonic_t_to_s_double(monotonic_t time) { + return (double)time / 1000.0 / 1000.0 / 1000.0; +} + +static monotonic_t start_time = 0; + +static inline monotonic_t monotonic_(void) { + struct timespec ts = {0}; +#ifdef CLOCK_HIGHRES + clock_gettime(CLOCK_HIGHRES, &ts); +#elif CLOCK_MONOTONIC_RAW + clock_gettime(CLOCK_MONOTONIC_RAW, &ts); +#else + clock_gettime(CLOCK_MONOTONIC, &ts); +#endif + return calc_nano_time(ts); +} + +static inline monotonic_t monotonic(void) { + return monotonic_() - start_time; +} + +static inline void init_monotonic(void) { + start_time = monotonic_(); +} diff --git a/kitty/mouse.c b/kitty/mouse.c index 341ac18b6..12e7935b3 100644 --- a/kitty/mouse.c +++ b/kitty/mouse.c @@ -13,6 +13,7 @@ #include #include "glfw-wrapper.h" #include "control-codes.h" +#include "monotonic.h" static MouseShape mouse_cursor_shape = BEAM; typedef enum MouseActions { PRESS, RELEASE, DRAG, MOVE } MouseAction; @@ -292,8 +293,8 @@ HANDLER(handle_move_event) { bool handle_in_kitty = !in_tracking_mode || has_terminal_select_modifiers; if (handle_in_kitty) { if (screen->selection.in_progress && button == GLFW_MOUSE_BUTTON_LEFT) { - double now = monotonic(); - if ((now - w->last_drag_scroll_at) >= 0.02 || mouse_cell_changed) { + monotonic_t now = monotonic(); + if ((now - w->last_drag_scroll_at) >= ms_to_monotonic_t(20ll) || mouse_cell_changed) { update_drag(false, w, false, 0); w->last_drag_scroll_at = now; } @@ -338,7 +339,7 @@ distance(double x1, double y1, double x2, double y2) { HANDLER(add_click) { ClickQueue *q = &w->click_queue; if (q->length == CLICK_QUEUE_SZ) { memmove(q->clicks, q->clicks + 1, sizeof(Click) * (CLICK_QUEUE_SZ - 1)); q->length--; } - double now = monotonic(); + monotonic_t now = monotonic(); #define N(n) (q->clicks[q->length - n]) N(0).at = now; N(0).button = button; N(0).modifiers = modifiers; N(0).x = w->mouse_pos.x; N(0).y = w->mouse_pos.y; q->length++; diff --git a/kitty/parser.c b/kitty/parser.c index 129d75b39..c433bfc42 100644 --- a/kitty/parser.c +++ b/kitty/parser.c @@ -9,6 +9,7 @@ #include "screen.h" #include "graphics.h" #include "charsets.h" +#include "monotonic.h" #include extern PyTypeObject Screen_Type; @@ -1196,7 +1197,7 @@ end: } static inline void -do_parse_bytes(Screen *screen, const uint8_t *read_buf, const size_t read_buf_sz, double now, PyObject *dump_callback DUMP_UNUSED) { +do_parse_bytes(Screen *screen, const uint8_t *read_buf, const size_t read_buf_sz, monotonic_t now, PyObject *dump_callback DUMP_UNUSED) { enum STATE {START, PARSE_PENDING, PARSE_READ_BUF, QUEUE_PENDING}; enum STATE state = START; size_t read_buf_pos = 0; @@ -1272,7 +1273,7 @@ FNAME(parse_bytes)(PyObject UNUSED *self, PyObject *args) { void -FNAME(parse_worker)(Screen *screen, PyObject *dump_callback, double now) { +FNAME(parse_worker)(Screen *screen, PyObject *dump_callback, monotonic_t now) { #ifdef DUMP_COMMANDS if (screen->read_buf_sz) { Py_XDECREF(PyObject_CallFunction(dump_callback, "sy#", "bytes", screen->read_buf, screen->read_buf_sz)); PyErr_Clear(); diff --git a/kitty/screen.c b/kitty/screen.c index 8d70745d0..f866cf1b5 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1730,7 +1730,7 @@ static PyObject* set_pending_timeout(Screen *self, PyObject *val) { if (!PyFloat_Check(val)) { PyErr_SetString(PyExc_TypeError, "timeout must be a float"); return NULL; } PyObject *ans = PyFloat_FromDouble(self->pending_mode.wait_time); - self->pending_mode.wait_time = PyFloat_AS_DOUBLE(val); + self->pending_mode.wait_time = s_double_to_monotonic_t(PyFloat_AS_DOUBLE(val)); return ans; } diff --git a/kitty/screen.h b/kitty/screen.h index 4eff12ee9..2e7f91ada 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -7,6 +7,7 @@ #pragma once #include "graphics.h" +#include "monotonic.h" typedef enum ScrollTypes { SCROLL_LINE = -999999, SCROLL_PAGE, SCROLL_FULL } ScrollType; @@ -86,13 +87,13 @@ typedef struct { bool *tabstops, *main_tabstops, *alt_tabstops; ScreenModes modes; ColorProfile *color_profile; - double start_visual_bell_at; + monotonic_t start_visual_bell_at; uint32_t parser_buf[PARSER_BUF_SZ]; unsigned int parser_state, parser_text_start, parser_buf_pos; bool parser_has_pending_text; uint8_t read_buf[READ_BUF_SZ], *write_buf; - double new_input_at; + monotonic_t new_input_at; size_t read_buf_sz, write_buf_sz, write_buf_used; pthread_mutex_t read_buf_lock, write_buf_lock; @@ -101,7 +102,7 @@ typedef struct { struct { size_t capacity, used, stop_buf_pos; uint8_t *buf; - double activated_at, wait_time; + monotonic_t activated_at, wait_time; int state; uint8_t stop_buf[32]; } pending_mode; @@ -110,8 +111,8 @@ typedef struct { } Screen; -void parse_worker(Screen *screen, PyObject *dump_callback, double now); -void parse_worker_dump(Screen *screen, PyObject *dump_callback, double now); +void parse_worker(Screen *screen, PyObject *dump_callback, monotonic_t now); +void parse_worker_dump(Screen *screen, PyObject *dump_callback, monotonic_t now); void screen_align(Screen*); void screen_restore_cursor(Screen *); void screen_save_cursor(Screen *); diff --git a/kitty/state.c b/kitty/state.c index f4920e85e..1e2f20cc7 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -300,9 +300,14 @@ color_as_int(PyObject *color) { #undef I } -static inline double -repaint_delay(PyObject *val) { - return (double)(PyLong_AsUnsignedLong(val)) / 1000.0; +static inline monotonic_t +parse_s_double_to_monotonic_t(PyObject *val) { + return s_double_to_monotonic_t(PyFloat_AsDouble(val)); +} + +static inline monotonic_t +parse_ms_long_to_monotonic_t(PyObject *val) { + return ms_to_monotonic_t(PyLong_AsUnsignedLong(val)); } static int kitty_mod = 0; @@ -390,11 +395,11 @@ PYWRAP1(set_options) { #define S(name, convert) SS(name, OPT(name), convert) SS(kitty_mod, kitty_mod, PyLong_AsLong); S(hide_window_decorations, PyObject_IsTrue); - S(visual_bell_duration, PyFloat_AsDouble); + S(visual_bell_duration, parse_s_double_to_monotonic_t); S(enable_audio_bell, PyObject_IsTrue); S(focus_follows_mouse, PyObject_IsTrue); - S(cursor_blink_interval, PyFloat_AsDouble); - S(cursor_stop_blinking_after, PyFloat_AsDouble); + S(cursor_blink_interval, parse_s_double_to_monotonic_t); + S(cursor_stop_blinking_after, parse_s_double_to_monotonic_t); S(background_opacity, PyFloat_AsDouble); S(dim_opacity, PyFloat_AsDouble); S(dynamic_background_opacity, PyObject_IsTrue); @@ -404,14 +409,14 @@ PYWRAP1(set_options) { S(cursor_shape, PyLong_AsLong); S(url_style, PyLong_AsUnsignedLong); S(tab_bar_edge, PyLong_AsLong); - S(mouse_hide_wait, PyFloat_AsDouble); + S(mouse_hide_wait, parse_s_double_to_monotonic_t); S(wheel_scroll_multiplier, PyFloat_AsDouble); S(touch_scroll_multiplier, PyFloat_AsDouble); S(open_url_modifiers, convert_mods); S(rectangle_select_modifiers, convert_mods); S(terminal_select_modifiers, convert_mods); - S(click_interval, PyFloat_AsDouble); - S(resize_debounce_time, PyFloat_AsDouble); + S(click_interval, parse_s_double_to_monotonic_t); + S(resize_debounce_time, parse_s_double_to_monotonic_t); S(url_color, color_as_int); S(background, color_as_int); S(foreground, color_as_int); @@ -420,8 +425,8 @@ PYWRAP1(set_options) { default_color = 0; S(inactive_border_color, color_as_int); S(bell_border_color, color_as_int); - S(repaint_delay, repaint_delay); - S(input_delay, repaint_delay); + S(repaint_delay, parse_ms_long_to_monotonic_t); + S(input_delay, parse_ms_long_to_monotonic_t); S(sync_to_monitor, PyObject_IsTrue); S(close_on_child_death, PyObject_IsTrue); S(window_alert_on_bell, PyObject_IsTrue); diff --git a/kitty/state.h b/kitty/state.h index cd21e302d..19358af44 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -7,6 +7,7 @@ #pragma once #include "data-types.h" #include "screen.h" +#include "monotonic.h" #define OPT(name) global_state.opts.name @@ -14,7 +15,8 @@ typedef enum { LEFT_EDGE, TOP_EDGE, RIGHT_EDGE, BOTTOM_EDGE } Edge; typedef enum { RESIZE_DRAW_STATIC, RESIZE_DRAW_SCALED, RESIZE_DRAW_BLANK, RESIZE_DRAW_SIZE } ResizeDrawStrategy; typedef struct { - double visual_bell_duration, cursor_blink_interval, cursor_stop_blinking_after, mouse_hide_wait, click_interval, wheel_scroll_multiplier, touch_scroll_multiplier; + monotonic_t visual_bell_duration, cursor_blink_interval, cursor_stop_blinking_after, mouse_hide_wait, click_interval; + double wheel_scroll_multiplier, touch_scroll_multiplier; bool enable_audio_bell; CursorShape cursor_shape; unsigned int open_url_modifiers; @@ -24,7 +26,7 @@ typedef struct { unsigned int scrollback_pager_history_size; char_type select_by_word_characters[256]; size_t select_by_word_characters_count; color_type url_color, background, foreground, active_border_color, inactive_border_color, bell_border_color; - double repaint_delay, input_delay; + monotonic_t repaint_delay, input_delay; bool focus_follows_mouse, hide_window_decorations; bool macos_hide_from_tasks, macos_quit_when_last_window_closed, macos_window_resizable, macos_traditional_fullscreen; unsigned int macos_option_as_alt; @@ -44,7 +46,7 @@ typedef struct { bool close_on_child_death; bool window_alert_on_bell; bool debug_keyboard; - double resize_debounce_time; + monotonic_t resize_debounce_time; MouseShape pointer_shape_when_grabbed; } Options; @@ -59,7 +61,7 @@ typedef struct { } WindowGeometry; typedef struct { - double at; + monotonic_t at; int button, modifiers; double x, y; } Click; @@ -83,7 +85,7 @@ typedef struct { } mouse_pos; WindowGeometry geometry; ClickQueue click_queue; - double last_drag_scroll_at; + monotonic_t last_drag_scroll_at; } Window; typedef struct { @@ -114,7 +116,7 @@ typedef struct { enum RENDER_STATE { RENDER_FRAME_NOT_REQUESTED, RENDER_FRAME_REQUESTED, RENDER_FRAME_READY }; typedef struct { - double last_resize_event_at; + monotonic_t last_resize_event_at; bool in_progress; bool from_os_notification; bool os_says_resize_complete; @@ -134,7 +136,7 @@ typedef struct { ScreenRenderData tab_bar_render_data; bool tab_bar_data_updated; bool is_focused; - double cursor_blink_zero_time, last_mouse_activity_at; + monotonic_t cursor_blink_zero_time, last_mouse_activity_at; double mouse_x, mouse_y; double logical_dpi_x, logical_dpi_y, font_sz_in_pts; bool mouse_button_pressed[20]; @@ -151,7 +153,7 @@ typedef struct { id_type temp_font_group_id; double pending_scroll_pixels; enum RENDER_STATE render_state; - double last_render_frame_received_at; + monotonic_t last_render_frame_received_at; id_type last_focused_counter; ssize_t gvao_idx; } OSWindow; @@ -239,8 +241,8 @@ void request_frame_render(OSWindow *w); void request_tick_callback(void); typedef void (* timer_callback_fun)(id_type, void*); typedef void (* tick_callback_fun)(void*); -id_type add_main_loop_timer(double interval, bool repeats, timer_callback_fun callback, void *callback_data, timer_callback_fun free_callback); +id_type add_main_loop_timer(monotonic_t interval, bool repeats, timer_callback_fun callback, void *callback_data, timer_callback_fun free_callback); void remove_main_loop_timer(id_type timer_id); -void update_main_loop_timer(id_type timer_id, double interval, bool enabled); +void update_main_loop_timer(id_type timer_id, monotonic_t interval, bool enabled); void run_main_loop(tick_callback_fun, void*); void stop_main_loop(void);