diff --git a/glfw/backend_utils.c b/glfw/backend_utils.c index 58ccb5fa6..7e628f57a 100644 --- a/glfw/backend_utils.c +++ b/glfw/backend_utils.c @@ -12,11 +12,25 @@ #include #include #include +#include #ifdef __NetBSD__ #define ppoll pollts #endif +static inline double +monotonic() { + 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) { eld->fds_count = 0; @@ -73,7 +87,6 @@ toggleWatch(EventLoopData *eld, id_type watch_id, int enabled) { } static id_type timer_counter = 0; -extern double glfwGetTime(void); static int compare_timers(const void *a_, const void *b_) { @@ -91,7 +104,7 @@ addTimer(EventLoopData *eld, double interval, int enabled, timer_callback_func c if (eld->timers_count >= sizeof(eld->timers)/sizeof(eld->timers[0])) return 0; Timer *t = eld->timers + eld->timers_count++; t->interval = interval; - t->trigger_at = enabled ? glfwGetTime() + interval : DBL_MAX; + t->trigger_at = enabled ? monotonic() + interval : DBL_MAX; t->callback = cb; t->callback_data = cb_data; t->id = ++timer_counter; @@ -108,7 +121,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 ? (glfwGetTime() + eld->timers[i].interval) : DBL_MAX; + double trigger_at = enabled ? (monotonic() + eld->timers[i].interval) : DBL_MAX; if (trigger_at != eld->timers[i].trigger_at) { eld->timers[i].trigger_at = trigger_at; update_timers(eld); @@ -133,7 +146,7 @@ double prepareForPoll(EventLoopData *eld, double timeout) { for (nfds_t i = 0; i < eld->fds_count; i++) eld->fds[i].revents = 0; if (!eld->timers_count || eld->timers[0].trigger_at == DBL_MAX) return timeout; - double now = glfwGetTime(), next_repeat_at = eld->timers[0].trigger_at; + double 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; } @@ -165,7 +178,7 @@ 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])]; unsigned num_dispatches = 0; - double now = glfwGetTime(); + double now = monotonic(); for (nfds_t i = 0; i < eld->timers_count && eld->timers[i].trigger_at < DBL_MAX; i++) { if (eld->timers[i].trigger_at <= now) { eld->timers[i].trigger_at = now + eld->timers[i].interval; @@ -201,7 +214,7 @@ pollForEvents(EventLoopData *eld, double timeout) { int read_ok = 0; timeout = prepareForPoll(eld, timeout); int result; - double end_time = glfwGetTime() + timeout; + double end_time = monotonic() + timeout; while(1) { if (timeout >= 0) { @@ -212,7 +225,7 @@ pollForEvents(EventLoopData *eld, double timeout) { read_ok = eld->watches[0].ready; break; } - timeout = end_time - glfwGetTime(); + timeout = end_time - monotonic(); if (timeout <= 0) break; if (result < 0 && (errno == EINTR || errno == EAGAIN)) continue; break; diff --git a/glfw/dbus_glfw.c b/glfw/dbus_glfw.c index 48041d72a..2db7ee97d 100644 --- a/glfw/dbus_glfw.c +++ b/glfw/dbus_glfw.c @@ -76,6 +76,7 @@ add_dbus_watch(DBusWatch *watch, void *data) { if (!watch_id) return FALSE; id_type *idp = malloc(sizeof(id_type)); if (!idp) return FALSE; + *idp = watch_id; dbus_watch_set_data(watch, idp, free); return TRUE; } @@ -92,6 +93,41 @@ toggle_dbus_watch(DBusWatch *watch, void *data) { if (idp) toggleWatch(dbus_data->eld, *idp, dbus_watch_get_enabled(watch)); } +static void +on_dbus_timer_ready(id_type timer_id, void *data) { + DBusTimeout *t = (DBusTimeout*)data; + dbus_timeout_handle(t); +} + + +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; + if (interval < 0) return FALSE; + id_type timer_id = addTimer(dbus_data->eld, interval, enabled, on_dbus_timer_ready, timeout); + if (!timer_id) return FALSE; + id_type *idp = malloc(sizeof(id_type)); + if (!idp) return FALSE; + *idp = timer_id; + dbus_timeout_set_data(timeout, idp, free); + return TRUE; + +} + +static void +remove_dbus_timeout(DBusTimeout *timeout, void *data) { + id_type *idp = dbus_timeout_get_data(timeout); + if (idp) removeTimer(dbus_data->eld, *idp); +} + +static void +toggle_dbus_timeout(DBusTimeout *timeout, void *data) { + id_type *idp = dbus_timeout_get_data(timeout); + if (idp) toggleTimer(dbus_data->eld, *idp, dbus_timeout_get_enabled(timeout)); +} + + DBusConnection* glfw_dbus_connect_to(const char *path, const char* err_msg) { DBusError err; @@ -114,6 +150,12 @@ glfw_dbus_connect_to(const char *path, const char* err_msg) { dbus_connection_unref(ans); return NULL; } + if (!dbus_connection_set_timeout_functions(ans, add_dbus_timeout, remove_dbus_timeout, toggle_dbus_timeout, NULL, NULL)) { + _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to set DBUS timeout functions on connection to: %s", path); + dbus_connection_close(ans); + dbus_connection_unref(ans); + return NULL; + } return ans; }