mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-20 23:44:59 +02:00
Implement timers for the linux event loops
Needed for dbus integration. Also cleanup the event handling code. X11 and Wayland now share most of their event polling and dispatch logic.
This commit is contained in:
150
glfw/backend_utils.c
vendored
150
glfw/backend_utils.c
vendored
@@ -8,8 +8,10 @@
|
|||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include "backend_utils.h"
|
#include "backend_utils.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <float.h>
|
||||||
|
|
||||||
#ifdef __NetBSD__
|
#ifdef __NetBSD__
|
||||||
#define ppoll pollts
|
#define ppoll pollts
|
||||||
@@ -42,24 +44,25 @@ addWatch(EventLoopData *eld, int fd, int events, int enabled, watch_callback_fun
|
|||||||
return w->id;
|
return w->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define removeX(which, item_id, update_func) {\
|
||||||
|
for (nfds_t i = 0; i < eld->which##_count; i++) { \
|
||||||
|
if (eld->which[i].id == item_id) { \
|
||||||
|
eld->which##_count--; \
|
||||||
|
if (i < eld->which##_count) { \
|
||||||
|
memmove(eld->which + i, eld->which + i + 1, sizeof(eld->which[0]) * (eld->which##_count - i)); \
|
||||||
|
} \
|
||||||
|
update_func(eld); break; \
|
||||||
|
}}}
|
||||||
|
|
||||||
void
|
void
|
||||||
removeWatch(EventLoopData *eld, id_type watch_id) {
|
removeWatch(EventLoopData *eld, id_type watch_id) {
|
||||||
for (nfds_t i = 0; i < eld->watches_count; i++) {
|
removeX(watches, watch_id, update_fds);
|
||||||
if (eld->watches[i].id == watch_id) {
|
|
||||||
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
|
void
|
||||||
toggleWatch(EventLoopData *eld, id_type watch_id, int enabled) {
|
toggleWatch(EventLoopData *eld, id_type watch_id, int enabled) {
|
||||||
for (nfds_t i = 0; i < eld->watches_count; i++) {
|
for (nfds_t i = 0; i < eld->watches_count; i++) {
|
||||||
if (eld->watches[i].fd == watch_id) {
|
if (eld->watches[i].id == watch_id) {
|
||||||
if (eld->watches[i].enabled != enabled) {
|
if (eld->watches[i].enabled != enabled) {
|
||||||
eld->watches[i].enabled = enabled;
|
eld->watches[i].enabled = enabled;
|
||||||
update_fds(eld);
|
update_fds(eld);
|
||||||
@@ -69,9 +72,72 @@ 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_) {
|
||||||
|
const Timer *a = (const Timer*)a_, *b = (const Timer*)b_;
|
||||||
|
return (a->trigger_at > b->trigger_at) ? 1 : (a->trigger_at < b->trigger_at) ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
update_timers(EventLoopData *eld) {
|
||||||
|
if (eld->timers_count > 1) qsort(eld->timers, eld->timers_count, sizeof(eld->timers[0]), compare_timers);
|
||||||
|
}
|
||||||
|
|
||||||
|
id_type
|
||||||
|
addTimer(EventLoopData *eld, double interval, int enabled, timer_callback_func cb, void *cb_data) {
|
||||||
|
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->callback = cb;
|
||||||
|
t->callback_data = cb_data;
|
||||||
|
t->id = ++timer_counter;
|
||||||
|
update_timers(eld);
|
||||||
|
return t->id;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
prepareForPoll(EventLoopData *eld) {
|
removeTimer(EventLoopData *eld, id_type timer_id) {
|
||||||
|
removeX(timers, timer_id, update_timers);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
if (trigger_at != eld->timers[i].trigger_at) {
|
||||||
|
eld->timers[i].trigger_at = trigger_at;
|
||||||
|
update_timers(eld);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
changeTimerInterval(EventLoopData *eld, id_type timer_id, double interval) {
|
||||||
|
for (nfds_t i = 0; i < eld->timers_count; i++) {
|
||||||
|
if (eld->timers[i].id == timer_id) {
|
||||||
|
eld->timers[i].interval = interval;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double
|
||||||
|
prepareForPoll(EventLoopData *eld, double timeout) {
|
||||||
for (nfds_t i = 0; i < eld->fds_count; i++) eld->fds[i].revents = 0;
|
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;
|
||||||
|
if (timeout < 0 || now + timeout > next_repeat_at) {
|
||||||
|
timeout = next_repeat_at <= now ? 0 : next_repeat_at - now;
|
||||||
|
}
|
||||||
|
return timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -82,7 +148,7 @@ pollWithTimeout(struct pollfd *fds, nfds_t nfds, double timeout) {
|
|||||||
return ppoll(fds, nfds, &tv, NULL);
|
return ppoll(fds, nfds, &tv, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
dispatchEvents(EventLoopData *eld) {
|
dispatchEvents(EventLoopData *eld) {
|
||||||
for (unsigned w = 0, f = 0; f < eld->fds_count; f++) {
|
for (unsigned w = 0, f = 0; f < eld->fds_count; f++) {
|
||||||
while(eld->watches[w].fd != eld->fds[f].fd) w++;
|
while(eld->watches[w].fd != eld->fds[f].fd) w++;
|
||||||
@@ -94,6 +160,29 @@ 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])];
|
||||||
|
unsigned num_dispatches = 0;
|
||||||
|
double now = glfwGetTime();
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
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 (num_dispatches) update_timers(eld);
|
||||||
|
return num_dispatches;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
drain_wakeup_fd(int fd, int events, void* data) {
|
drain_wakeup_fd(int fd, int events, void* data) {
|
||||||
static char drain_buf[64];
|
static char drain_buf[64];
|
||||||
@@ -106,6 +195,41 @@ initPollData(EventLoopData *eld, int wakeup_fd, int display_fd) {
|
|||||||
addWatch(eld, wakeup_fd, POLLIN, 1, drain_wakeup_fd, NULL);
|
addWatch(eld, wakeup_fd, POLLIN, 1, drain_wakeup_fd, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
pollForEvents(EventLoopData *eld, double timeout) {
|
||||||
|
int read_ok = 0;
|
||||||
|
timeout = prepareForPoll(eld, timeout);
|
||||||
|
int result;
|
||||||
|
double end_time = glfwGetTime() + timeout;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
if (timeout >= 0) {
|
||||||
|
result = pollWithTimeout(eld->fds, eld->fds_count, timeout);
|
||||||
|
dispatchTimers(eld);
|
||||||
|
if (result > 0) {
|
||||||
|
dispatchEvents(eld);
|
||||||
|
read_ok = eld->watches[0].ready;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
timeout = end_time - glfwGetTime();
|
||||||
|
if (timeout <= 0) break;
|
||||||
|
if (result < 0 && (errno == EINTR || errno == EAGAIN)) continue;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
result = poll(eld->fds, eld->fds_count, -1);
|
||||||
|
dispatchTimers(eld);
|
||||||
|
if (result > 0) {
|
||||||
|
dispatchEvents(eld);
|
||||||
|
read_ok = eld->watches[0].ready;
|
||||||
|
}
|
||||||
|
if (result < 0 && (errno == EINTR || errno == EAGAIN)) continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return read_ok;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
closeFds(int *fds, size_t count) {
|
closeFds(int *fds, size_t count) {
|
||||||
while(count--) {
|
while(count--) {
|
||||||
|
|||||||
23
glfw/backend_utils.h
vendored
23
glfw/backend_utils.h
vendored
@@ -28,8 +28,9 @@
|
|||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
typedef void(*watch_callback_func)(int, int, void*);
|
|
||||||
typedef unsigned long long id_type;
|
typedef unsigned long long id_type;
|
||||||
|
typedef void(*watch_callback_func)(int, int, void*);
|
||||||
|
typedef void(*timer_callback_func)(id_type, void*);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int fd, events, enabled, ready;
|
int fd, events, enabled, ready;
|
||||||
@@ -38,19 +39,33 @@ typedef struct {
|
|||||||
id_type id;
|
id_type id;
|
||||||
} Watch;
|
} Watch;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
id_type id;
|
||||||
|
double interval, trigger_at;
|
||||||
|
timer_callback_func callback;
|
||||||
|
void *callback_data;
|
||||||
|
} Timer;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct pollfd fds[32];
|
struct pollfd fds[32];
|
||||||
int wakeupFds[2];
|
int wakeupFds[2];
|
||||||
nfds_t watches_count, fds_count;
|
nfds_t watches_count, fds_count, timers_count;
|
||||||
Watch watches[32];
|
Watch watches[32];
|
||||||
|
Timer timers[128];
|
||||||
} EventLoopData;
|
} EventLoopData;
|
||||||
|
|
||||||
|
|
||||||
id_type addWatch(EventLoopData *eld, int fd, int events, int enabled, watch_callback_func cb, void *cb_data);
|
id_type addWatch(EventLoopData *eld, int fd, int events, int enabled, watch_callback_func cb, void *cb_data);
|
||||||
void removeWatch(EventLoopData *eld, id_type watch_id);
|
void removeWatch(EventLoopData *eld, id_type watch_id);
|
||||||
void toggleWatch(EventLoopData *eld, id_type watch_id, int enabled);
|
void toggleWatch(EventLoopData *eld, id_type watch_id, int enabled);
|
||||||
void prepareForPoll(EventLoopData *eld);
|
id_type addTimer(EventLoopData *eld, double interval, int enabled, timer_callback_func cb, void *cb_data);
|
||||||
|
void removeTimer(EventLoopData *eld, id_type timer_id);
|
||||||
|
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 pollWithTimeout(struct pollfd *fds, nfds_t nfds, double timeout);
|
||||||
void dispatchEvents(EventLoopData *eld);
|
int pollForEvents(EventLoopData *eld, double timeout);
|
||||||
|
unsigned dispatchTimers(EventLoopData *eld);
|
||||||
void closeFds(int *fds, size_t count);
|
void closeFds(int *fds, size_t count);
|
||||||
void initPollData(EventLoopData *eld, int wakeup_fd, int display_fd);
|
void initPollData(EventLoopData *eld, int wakeup_fd, int display_fd);
|
||||||
|
|||||||
18
glfw/wl_init.c
vendored
18
glfw/wl_init.c
vendored
@@ -407,6 +407,15 @@ static void keyboardHandleLeave(void* data,
|
|||||||
_glfwInputWindowFocus(window, GLFW_FALSE);
|
_glfwInputWindowFocus(window, GLFW_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dispatchPendingKeyRepeats(id_type timer_id, void *data) {
|
||||||
|
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, ((double)_glfw.wl.keyboardRepeatRate) / 1000.0);
|
||||||
|
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void keyboardHandleKey(void* data,
|
static void keyboardHandleKey(void* data,
|
||||||
struct wl_keyboard* keyboard,
|
struct wl_keyboard* keyboard,
|
||||||
uint32_t serial,
|
uint32_t serial,
|
||||||
@@ -419,14 +428,18 @@ static void keyboardHandleKey(void* data,
|
|||||||
return;
|
return;
|
||||||
int action = state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE;
|
int action = state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE;
|
||||||
glfw_xkb_handle_key_event(window, &_glfw.wl.xkb, key, action);
|
glfw_xkb_handle_key_event(window, &_glfw.wl.xkb, key, action);
|
||||||
_glfw.wl.keyRepeatInfo.nextRepeatAt = 0;
|
GLFWbool repeatable = GLFW_FALSE;
|
||||||
|
|
||||||
if (action == GLFW_PRESS && _glfw.wl.keyboardRepeatRate > 0 && glfw_xkb_should_repeat(&_glfw.wl.xkb, key))
|
if (action == GLFW_PRESS && _glfw.wl.keyboardRepeatRate > 0 && glfw_xkb_should_repeat(&_glfw.wl.xkb, key))
|
||||||
{
|
{
|
||||||
_glfw.wl.keyRepeatInfo.key = key;
|
_glfw.wl.keyRepeatInfo.key = key;
|
||||||
_glfw.wl.keyRepeatInfo.nextRepeatAt = glfwGetTime() + (double)(_glfw.wl.keyboardRepeatDelay) / 1000.0;
|
repeatable = GLFW_TRUE;
|
||||||
_glfw.wl.keyRepeatInfo.keyboardFocus = window;
|
_glfw.wl.keyRepeatInfo.keyboardFocus = window;
|
||||||
}
|
}
|
||||||
|
if (repeatable) {
|
||||||
|
changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, (double)(_glfw.wl.keyboardRepeatDelay) / 1000.0);
|
||||||
|
}
|
||||||
|
toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, repeatable ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void keyboardHandleModifiers(void* data,
|
static void keyboardHandleModifiers(void* data,
|
||||||
@@ -666,6 +679,7 @@ int _glfwPlatformInit(void)
|
|||||||
}
|
}
|
||||||
initPollData(&_glfw.wl.eventLoopData, _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_dbus_init(&_glfw.wl.dbus, &_glfw.wl.eventLoopData);
|
glfw_dbus_init(&_glfw.wl.dbus, &_glfw.wl.eventLoopData);
|
||||||
|
_glfw.wl.keyRepeatInfo.keyRepeatTimer = addTimer(&_glfw.wl.eventLoopData, 0.5, 0, dispatchPendingKeyRepeats, NULL);
|
||||||
|
|
||||||
_glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
|
_glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
|
||||||
wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL);
|
wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL);
|
||||||
|
|||||||
2
glfw/wl_platform.h
vendored
2
glfw/wl_platform.h
vendored
@@ -205,7 +205,7 @@ typedef struct _GLFWlibraryWayland
|
|||||||
int32_t keyboardRepeatDelay;
|
int32_t keyboardRepeatDelay;
|
||||||
struct {
|
struct {
|
||||||
uint32_t key;
|
uint32_t key;
|
||||||
double nextRepeatAt;
|
id_type keyRepeatTimer;
|
||||||
_GLFWwindow* keyboardFocus;
|
_GLFWwindow* keyboardFocus;
|
||||||
} keyRepeatInfo;
|
} keyRepeatInfo;
|
||||||
_GLFWXKBData xkb;
|
_GLFWXKBData xkb;
|
||||||
|
|||||||
45
glfw/wl_window.c
vendored
45
glfw/wl_window.c
vendored
@@ -688,34 +688,14 @@ static GLFWbool createXdgSurface(_GLFWwindow* window)
|
|||||||
return GLFW_TRUE;
|
return GLFW_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
dispatchPendingKeyRepeats() {
|
|
||||||
if (_glfw.wl.keyRepeatInfo.nextRepeatAt <= 0 || _glfw.wl.keyRepeatInfo.keyboardFocus != _glfw.wl.keyboardFocus || _glfw.wl.keyboardRepeatRate == 0) return;
|
|
||||||
double now = glfwGetTime();
|
|
||||||
while (_glfw.wl.keyRepeatInfo.nextRepeatAt <= now) {
|
|
||||||
glfw_xkb_handle_key_event(_glfw.wl.keyRepeatInfo.keyboardFocus, &_glfw.wl.xkb, _glfw.wl.keyRepeatInfo.key, GLFW_REPEAT);
|
|
||||||
_glfw.wl.keyRepeatInfo.nextRepeatAt += 1.0 / _glfw.wl.keyboardRepeatRate;
|
|
||||||
now = glfwGetTime();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static double
|
|
||||||
adjustTimeoutForKeyRepeat(double timeout) {
|
|
||||||
if (_glfw.wl.keyRepeatInfo.nextRepeatAt <= 0 || _glfw.wl.keyRepeatInfo.keyboardFocus != _glfw.wl.keyboardFocus || _glfw.wl.keyboardRepeatRate == 0) return timeout;
|
|
||||||
double now = glfwGetTime();
|
|
||||||
if (timeout < 0 || now + timeout > _glfw.wl.keyRepeatInfo.nextRepeatAt) {
|
|
||||||
timeout = _glfw.wl.keyRepeatInfo.nextRepeatAt <= now ? 0 : ( (_glfw.wl.keyRepeatInfo.nextRepeatAt - now) + 0.001 );
|
|
||||||
}
|
|
||||||
return timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handleEvents(double timeout)
|
handleEvents(double timeout)
|
||||||
{
|
{
|
||||||
struct wl_display* display = _glfw.wl.display;
|
struct wl_display* display = _glfw.wl.display;
|
||||||
|
|
||||||
while (wl_display_prepare_read(display) != 0)
|
while (wl_display_prepare_read(display) != 0) {
|
||||||
wl_display_dispatch_pending(display);
|
wl_display_dispatch_pending(display);
|
||||||
|
}
|
||||||
|
|
||||||
// If an error different from EAGAIN happens, we have likely been
|
// If an error different from EAGAIN happens, we have likely been
|
||||||
// disconnected from the Wayland session, try to handle that the best we
|
// disconnected from the Wayland session, try to handle that the best we
|
||||||
@@ -732,24 +712,8 @@ handleEvents(double timeout)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchPendingKeyRepeats();
|
GLFWbool display_read_ok = pollForEvents(&_glfw.wl.eventLoopData, timeout);
|
||||||
timeout = adjustTimeoutForKeyRepeat(timeout);
|
if (display_read_ok) {
|
||||||
GLFWbool read_ok = GLFW_FALSE;
|
|
||||||
prepareForPoll(&_glfw.wl.eventLoopData);
|
|
||||||
|
|
||||||
if (timeout >= 0) {
|
|
||||||
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, _glfw.wl.eventLoopData.fds_count, -1) > 0) {
|
|
||||||
dispatchEvents(&_glfw.wl.eventLoopData);
|
|
||||||
read_ok = _glfw.wl.eventLoopData.watches[0].ready;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (read_ok) {
|
|
||||||
wl_display_read_events(display);
|
wl_display_read_events(display);
|
||||||
wl_display_dispatch_pending(display);
|
wl_display_dispatch_pending(display);
|
||||||
}
|
}
|
||||||
@@ -757,7 +721,6 @@ handleEvents(double timeout)
|
|||||||
{
|
{
|
||||||
wl_display_cancel_read(display);
|
wl_display_cancel_read(display);
|
||||||
}
|
}
|
||||||
dispatchPendingKeyRepeats();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translates a GLFW standard cursor to a theme cursor name
|
// Translates a GLFW standard cursor to a theme cursor name
|
||||||
|
|||||||
84
glfw/x11_window.c
vendored
84
glfw/x11_window.c
vendored
@@ -54,38 +54,31 @@
|
|||||||
// This avoids blocking other threads via the per-display Xlib lock that also
|
// This avoids blocking other threads via the per-display Xlib lock that also
|
||||||
// covers GLX functions
|
// covers GLX functions
|
||||||
//
|
//
|
||||||
static GLFWbool waitForEvent(double* timeout)
|
void _glfwDispatchX11Events(void);
|
||||||
{
|
|
||||||
nfds_t count = _glfw.x11.eventLoopData.fds_count;
|
|
||||||
|
|
||||||
for (;;)
|
static void
|
||||||
{
|
handleEvents(double timeout) {
|
||||||
prepareForPoll(&_glfw.x11.eventLoopData);
|
int display_read_ok = pollForEvents(&_glfw.x11.eventLoopData, timeout);
|
||||||
if (timeout)
|
if (display_read_ok) _glfwDispatchX11Events();
|
||||||
{
|
}
|
||||||
const uint64_t base = _glfwPlatformGetTimerValue();
|
|
||||||
const int result = pollWithTimeout(_glfw.x11.eventLoopData.fds, count, *timeout);
|
|
||||||
*timeout -= (_glfwPlatformGetTimerValue() - base) /
|
|
||||||
(double) _glfwPlatformGetTimerFrequency();
|
|
||||||
|
|
||||||
if (result > 0) {
|
static GLFWbool
|
||||||
dispatchEvents(&_glfw.x11.eventLoopData);
|
waitForX11Event(double timeout) {
|
||||||
return GLFW_TRUE;
|
// returns true iff there is X11 data waiting to be read, does not run watches and timers
|
||||||
}
|
double end_time = glfwGetTime() + timeout;
|
||||||
if (result == 0)
|
while(GLFW_TRUE) {
|
||||||
return GLFW_FALSE;
|
if (timeout >= 0) {
|
||||||
if (*timeout > 0 && (errno == EINTR || errno == EAGAIN)) continue;
|
const int result = pollWithTimeout(_glfw.x11.eventLoopData.fds, 1, timeout);
|
||||||
|
if (result > 0) return GLFW_TRUE;
|
||||||
|
timeout = end_time - glfwGetTime();
|
||||||
|
if (timeout <= 0) return GLFW_FALSE;
|
||||||
|
if (result < 0 && (errno == EINTR || errno == EAGAIN)) continue;
|
||||||
|
return GLFW_FALSE;
|
||||||
|
} else {
|
||||||
|
const int result = poll(_glfw.x11.eventLoopData.fds, 1, -1);
|
||||||
|
if (result > 0) return GLFW_TRUE;
|
||||||
|
if (result < 0 && (errno == EINTR || errno == EAGAIN)) continue;
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
}
|
|
||||||
else {
|
|
||||||
const int result = poll(_glfw.x11.eventLoopData.fds, count, -1);
|
|
||||||
if (result > 0) {
|
|
||||||
dispatchEvents(&_glfw.x11.eventLoopData);
|
|
||||||
return GLFW_TRUE;
|
|
||||||
}
|
|
||||||
if (result == 0)
|
|
||||||
return GLFW_FALSE;
|
|
||||||
if (errno != EINTR && errno != EAGAIN) return GLFW_FALSE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,14 +89,13 @@ static GLFWbool waitForEvent(double* timeout)
|
|||||||
static GLFWbool waitForVisibilityNotify(_GLFWwindow* window)
|
static GLFWbool waitForVisibilityNotify(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
XEvent dummy;
|
XEvent dummy;
|
||||||
double timeout = 0.1;
|
|
||||||
|
|
||||||
while (!XCheckTypedWindowEvent(_glfw.x11.display,
|
while (!XCheckTypedWindowEvent(_glfw.x11.display,
|
||||||
window->x11.handle,
|
window->x11.handle,
|
||||||
VisibilityNotify,
|
VisibilityNotify,
|
||||||
&dummy))
|
&dummy))
|
||||||
{
|
{
|
||||||
if (!waitForEvent(&timeout))
|
if (!waitForX11Event(0.1))
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -975,7 +967,7 @@ static const char* getSelectionString(Atom selection)
|
|||||||
SelectionNotify,
|
SelectionNotify,
|
||||||
¬ification))
|
¬ification))
|
||||||
{
|
{
|
||||||
waitForEvent(NULL);
|
waitForX11Event(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notification.xselection.property == None)
|
if (notification.xselection.property == None)
|
||||||
@@ -1011,7 +1003,7 @@ static const char* getSelectionString(Atom selection)
|
|||||||
isSelPropNewValueNotify,
|
isSelPropNewValueNotify,
|
||||||
(XPointer) ¬ification))
|
(XPointer) ¬ification))
|
||||||
{
|
{
|
||||||
waitForEvent(NULL);
|
waitForX11Event(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
XFree(data);
|
XFree(data);
|
||||||
@@ -1843,7 +1835,7 @@ void _glfwPushSelectionToManagerX11(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
waitForEvent(NULL);
|
waitForX11Event(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2133,7 +2125,6 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
|||||||
_glfw.x11.NET_REQUEST_FRAME_EXTENTS)
|
_glfw.x11.NET_REQUEST_FRAME_EXTENTS)
|
||||||
{
|
{
|
||||||
XEvent event;
|
XEvent event;
|
||||||
double timeout = 0.5;
|
|
||||||
|
|
||||||
// Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to
|
// Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to
|
||||||
// function before the window is mapped
|
// function before the window is mapped
|
||||||
@@ -2150,7 +2141,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
|||||||
isFrameExtentsEvent,
|
isFrameExtentsEvent,
|
||||||
(XPointer) window))
|
(XPointer) window))
|
||||||
{
|
{
|
||||||
if (!waitForEvent(&timeout))
|
if (!waitForX11Event(0.5))
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue");
|
"X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue");
|
||||||
@@ -2551,8 +2542,7 @@ void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
|
|||||||
PropModeReplace, (unsigned char*) &value, 1);
|
PropModeReplace, (unsigned char*) &value, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformPollEvents(void)
|
void _glfwDispatchX11Events(void) {
|
||||||
{
|
|
||||||
_GLFWwindow* window;
|
_GLFWwindow* window;
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
@@ -2585,23 +2575,19 @@ void _glfwPlatformPollEvents(void)
|
|||||||
XFlush(_glfw.x11.display);
|
XFlush(_glfw.x11.display);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformPollEvents(void)
|
||||||
|
{
|
||||||
|
handleEvents(0);
|
||||||
|
}
|
||||||
|
|
||||||
void _glfwPlatformWaitEvents(void)
|
void _glfwPlatformWaitEvents(void)
|
||||||
{
|
{
|
||||||
while (!XPending(_glfw.x11.display))
|
handleEvents(-1);
|
||||||
waitForEvent(NULL);
|
|
||||||
|
|
||||||
_glfwPlatformPollEvents();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformWaitEventsTimeout(double timeout)
|
void _glfwPlatformWaitEventsTimeout(double timeout)
|
||||||
{
|
{
|
||||||
while (!XPending(_glfw.x11.display))
|
handleEvents(timeout);
|
||||||
{
|
|
||||||
if (!waitForEvent(&timeout))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
_glfwPlatformPollEvents();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformPostEmptyEvent(void)
|
void _glfwPlatformPostEmptyEvent(void)
|
||||||
|
|||||||
Reference in New Issue
Block a user