Switch to using the GLFW main loop
This commit is contained in:
parent
d593ccba2f
commit
bef9490fa8
4
glfw/x11_init.c
vendored
4
glfw/x11_init.c
vendored
@ -787,7 +787,7 @@ void _glfwPlatformRunMainLoop(GLFWtickcallback callback, void* data) {
|
||||
keep_going = GLFW_TRUE;
|
||||
tick_callback_requested = GLFW_FALSE;
|
||||
while(keep_going) {
|
||||
if (tick_callback_requested) {
|
||||
while (tick_callback_requested) {
|
||||
tick_callback_requested = GLFW_FALSE;
|
||||
callback(data);
|
||||
}
|
||||
@ -799,6 +799,6 @@ unsigned long long _glfwPlatformAddTimer(double interval, bool repeats, GLFWuser
|
||||
return addTimer(&_glfw.x11.eventLoopData, "user timer", interval, 1, repeats, callback, callback_data, free_callback);
|
||||
}
|
||||
|
||||
void _glfwRemoveTimer(unsigned long long timer_id) {
|
||||
void _glfwPlatformRemoveTimer(unsigned long long timer_id) {
|
||||
removeTimer(&_glfw.x11.eventLoopData, timer_id);
|
||||
}
|
||||
|
||||
@ -768,12 +768,6 @@ cm_thread_write(PyObject UNUSED *self, PyObject *args) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static inline void
|
||||
wait_for_events() {
|
||||
event_loop_wait(maximum_wait);
|
||||
maximum_wait = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
python_timer_callback(id_type timer_id, void *data) {
|
||||
PyObject *callback = (PyObject*)data;
|
||||
@ -867,20 +861,37 @@ set_cocoa_pending_action(CocoaPendingAction action, const char *wd) {
|
||||
cocoa_pending_actions |= action;
|
||||
// The main loop may be blocking on the event queue, if e.g. unfocused.
|
||||
// Unjam it so the pending action is processed right now.
|
||||
unjam_event_loop();
|
||||
wakeup_main_loop();
|
||||
}
|
||||
#endif
|
||||
|
||||
static PyObject*
|
||||
main_loop(ChildMonitor *self, PyObject *a UNUSED) {
|
||||
#define main_loop_doc "The main thread loop"
|
||||
bool has_open_windows = true;
|
||||
static id_type state_check_timer = 0;
|
||||
static void process_global_state(void *data);
|
||||
|
||||
static void
|
||||
do_state_check(id_type timer_id UNUSED, void *data) {
|
||||
ChildMonitor *self = data;
|
||||
process_global_state(self);
|
||||
}
|
||||
|
||||
static void
|
||||
request_global_state_check_in(double seconds, ChildMonitor *self) {
|
||||
if (state_check_timer) remove_main_loop_timer(state_check_timer);
|
||||
state_check_timer = add_main_loop_timer(seconds, false, do_state_check, self, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
process_global_state(void *data) {
|
||||
ChildMonitor *self = data;
|
||||
if (state_check_timer) {
|
||||
remove_main_loop_timer(state_check_timer);
|
||||
state_check_timer = 0;
|
||||
}
|
||||
maximum_wait = -1;
|
||||
|
||||
while (has_open_windows) {
|
||||
double now = monotonic();
|
||||
if (global_state.has_pending_resizes) process_pending_resizes(now);
|
||||
render(now);
|
||||
wait_for_events();
|
||||
#ifdef __APPLE__
|
||||
if (cocoa_pending_actions) {
|
||||
if (cocoa_pending_actions & PREFERENCES_WINDOW) { call_boss(edit_config_file, NULL); }
|
||||
@ -903,8 +914,21 @@ main_loop(ChildMonitor *self, PyObject *a UNUSED) {
|
||||
#endif
|
||||
}
|
||||
report_reaped_pids();
|
||||
has_open_windows = process_pending_closes(self);
|
||||
bool has_open_windows = process_pending_closes(self);
|
||||
if (has_open_windows) {
|
||||
if (maximum_wait >= 0) {
|
||||
if (maximum_wait == 0) request_tick_callback();
|
||||
else request_global_state_check_in(maximum_wait, self);
|
||||
}
|
||||
} else {
|
||||
stop_main_loop();
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
main_loop(ChildMonitor *self, PyObject *a UNUSED) {
|
||||
#define main_loop_doc "The main thread loop"
|
||||
run_main_loop(process_global_state, self);
|
||||
#ifdef __APPLE__
|
||||
if (cocoa_pending_actions_wd) { free(cocoa_pending_actions_wd); cocoa_pending_actions_wd = NULL; }
|
||||
#endif
|
||||
|
||||
70
kitty/glfw.c
70
kitty/glfw.c
@ -24,7 +24,6 @@ extern double cocoa_cursor_blink_interval(void);
|
||||
#endif
|
||||
|
||||
static GLFWcursor *standard_cursor = NULL, *click_cursor = NULL, *arrow_cursor = NULL;
|
||||
static bool event_loop_blocking_with_no_timeout = false;
|
||||
|
||||
static void set_os_window_dpi(OSWindow *w);
|
||||
|
||||
@ -60,19 +59,6 @@ update_os_window_viewport(OSWindow *window, bool notify_boss) {
|
||||
}
|
||||
}
|
||||
|
||||
// On Cocoa, glfwWaitEvents() can block indefinitely because of the way Cocoa
|
||||
// works. See https://github.com/glfw/glfw/issues/1251. I have noticed this
|
||||
// happening in particular with window resize events, when waiting with no
|
||||
// timeout. See https://github.com/kovidgoyal/kitty/issues/458
|
||||
// So we use an unlovely hack to workaround that case
|
||||
void
|
||||
unjam_event_loop() {
|
||||
#ifdef __APPLE__
|
||||
if (event_loop_blocking_with_no_timeout)
|
||||
wakeup_main_loop();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// callbacks {{{
|
||||
|
||||
@ -120,6 +106,27 @@ blank_os_window(OSWindow *w) {
|
||||
blank_canvas(w->is_semi_transparent ? w->background_opacity : 1.0f);
|
||||
}
|
||||
|
||||
static void
|
||||
window_close_callback(GLFWwindow* window) {
|
||||
if (!set_callback_window(window)) return;
|
||||
request_tick_callback();
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
window_occlusion_callback(GLFWwindow *window, bool occluded UNUSED) {
|
||||
if (!set_callback_window(window)) return;
|
||||
request_tick_callback();
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
window_iconify_callback(GLFWwindow *window, int iconified UNUSED) {
|
||||
if (!set_callback_window(window)) return;
|
||||
request_tick_callback();
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
framebuffer_size_callback(GLFWwindow *w, int width, int height) {
|
||||
if (!set_callback_window(w)) return;
|
||||
@ -127,7 +134,6 @@ framebuffer_size_callback(GLFWwindow *w, int width, int height) {
|
||||
OSWindow *window = global_state.callback_os_window;
|
||||
window->has_pending_resizes = true; global_state.has_pending_resizes = true;
|
||||
window->last_resize_event_at = monotonic();
|
||||
unjam_event_loop();
|
||||
#ifdef __APPLE__
|
||||
// Cocoa starts a sub-loop inside wait events which means main_loop
|
||||
// stays stuck and no rendering happens. This causes the window to be
|
||||
@ -139,6 +145,7 @@ framebuffer_size_callback(GLFWwindow *w, int width, int height) {
|
||||
swap_window_buffers(global_state.callback_os_window);
|
||||
}
|
||||
#endif
|
||||
request_tick_callback();
|
||||
} else log_error("Ignoring resize request for tiny size: %dx%d", width, height);
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
@ -152,6 +159,7 @@ dpi_change_callback(GLFWwindow *w, float x_scale UNUSED, float y_scale UNUSED) {
|
||||
window->has_pending_resizes = true; global_state.has_pending_resizes = true;
|
||||
window->last_resize_event_at = monotonic();
|
||||
global_state.callback_os_window = NULL;
|
||||
request_tick_callback();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -159,6 +167,7 @@ refresh_callback(GLFWwindow *w) {
|
||||
if (!set_callback_window(w)) return;
|
||||
global_state.callback_os_window->is_damaged = true;
|
||||
global_state.callback_os_window = NULL;
|
||||
request_tick_callback();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -170,6 +179,7 @@ key_callback(GLFWwindow *w, int key, int scancode, int action, int mods, const c
|
||||
}
|
||||
if (is_window_ready_for_callbacks()) on_key_input(key, scancode, action, mods, text, state);
|
||||
global_state.callback_os_window = NULL;
|
||||
request_tick_callback();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -180,6 +190,7 @@ cursor_enter_callback(GLFWwindow *w, int entered) {
|
||||
double now = monotonic();
|
||||
global_state.callback_os_window->last_mouse_activity_at = now;
|
||||
if (is_window_ready_for_callbacks()) enter_event();
|
||||
request_tick_callback();
|
||||
}
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
@ -194,6 +205,7 @@ mouse_button_callback(GLFWwindow *w, int button, int action, int mods) {
|
||||
global_state.callback_os_window->mouse_button_pressed[button] = action == GLFW_PRESS ? true : false;
|
||||
if (is_window_ready_for_callbacks()) mouse_event(button, mods, action);
|
||||
}
|
||||
request_tick_callback();
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
|
||||
@ -207,6 +219,7 @@ cursor_pos_callback(GLFWwindow *w, double x, double y) {
|
||||
global_state.callback_os_window->mouse_x = x * global_state.callback_os_window->viewport_x_ratio;
|
||||
global_state.callback_os_window->mouse_y = y * global_state.callback_os_window->viewport_y_ratio;
|
||||
if (is_window_ready_for_callbacks()) mouse_event(-1, 0, -1);
|
||||
request_tick_callback();
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
|
||||
@ -217,6 +230,7 @@ scroll_callback(GLFWwindow *w, double xoffset, double yoffset, int flags) {
|
||||
double 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();
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
|
||||
@ -239,6 +253,7 @@ window_focus_callback(GLFWwindow *w, int focused) {
|
||||
WINDOW_CALLBACK(on_focus, "O", focused ? Py_True : Py_False);
|
||||
glfwUpdateIMEState(global_state.callback_os_window->handle, 1, focused, 0, 0, 0);
|
||||
}
|
||||
request_tick_callback();
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
|
||||
@ -250,6 +265,7 @@ drop_callback(GLFWwindow *w, int count, const char **paths) {
|
||||
for (int i = 0; i < count; i++) PyTuple_SET_ITEM(p, i, PyUnicode_FromString(paths[i]));
|
||||
WINDOW_CALLBACK(on_drop, "O", p);
|
||||
Py_CLEAR(p);
|
||||
request_tick_callback();
|
||||
}
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
@ -420,7 +436,6 @@ on_application_reopen(int has_visible_windows) {
|
||||
if (has_visible_windows) return true;
|
||||
set_cocoa_pending_action(NEW_OS_WINDOW, NULL);
|
||||
// Without unjam wait_for_events() blocks until the next event
|
||||
unjam_event_loop();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -585,15 +600,21 @@ create_os_window(PyObject UNUSED *self, PyObject *args) {
|
||||
if (logo.pixels && logo.width && logo.height) glfwSetWindowIcon(glfw_window, 1, &logo);
|
||||
glfwSetCursor(glfw_window, standard_cursor);
|
||||
update_os_window_viewport(w, false);
|
||||
// missing pos callback
|
||||
// missing size callback
|
||||
glfwSetWindowCloseCallback(glfw_window, window_close_callback);
|
||||
glfwSetWindowRefreshCallback(glfw_window, refresh_callback);
|
||||
glfwSetWindowFocusCallback(glfw_window, window_focus_callback);
|
||||
glfwSetWindowOcclusionCallback(glfw_window, window_occlusion_callback);
|
||||
glfwSetWindowIconifyCallback(glfw_window, window_iconify_callback);
|
||||
// missing maximize/restore callback
|
||||
glfwSetFramebufferSizeCallback(glfw_window, framebuffer_size_callback);
|
||||
glfwSetWindowContentScaleCallback(glfw_window, dpi_change_callback);
|
||||
glfwSetWindowRefreshCallback(glfw_window, refresh_callback);
|
||||
glfwSetCursorEnterCallback(glfw_window, cursor_enter_callback);
|
||||
glfwSetMouseButtonCallback(glfw_window, mouse_button_callback);
|
||||
glfwSetScrollCallback(glfw_window, scroll_callback);
|
||||
glfwSetCursorPosCallback(glfw_window, cursor_pos_callback);
|
||||
glfwSetCursorEnterCallback(glfw_window, cursor_enter_callback);
|
||||
glfwSetScrollCallback(glfw_window, scroll_callback);
|
||||
glfwSetKeyboardCallback(glfw_window, key_callback);
|
||||
glfwSetWindowFocusCallback(glfw_window, window_focus_callback);
|
||||
glfwSetDropCallback(glfw_window, drop_callback);
|
||||
#ifdef __APPLE__
|
||||
if (glfwGetCocoaWindow) cocoa_make_window_resizable(glfwGetCocoaWindow(glfw_window), OPT(macos_window_resizable));
|
||||
@ -892,14 +913,9 @@ swap_window_buffers(OSWindow *os_window) {
|
||||
glfwSwapBuffers(os_window->handle);
|
||||
}
|
||||
|
||||
void
|
||||
event_loop_wait(double timeout) {
|
||||
if (timeout < 0) { event_loop_blocking_with_no_timeout = true; glfwWaitEvents(); event_loop_blocking_with_no_timeout = false; }
|
||||
else glfwWaitEventsTimeout(timeout);
|
||||
}
|
||||
|
||||
void
|
||||
wakeup_main_loop() {
|
||||
request_tick_callback();
|
||||
glfwPostEmptyEvent();
|
||||
}
|
||||
|
||||
@ -1064,6 +1080,7 @@ cocoa_frame_request_callback(GLFWwindow *window) {
|
||||
for (size_t i = 0; i < global_state.num_os_windows; i++) {
|
||||
if (global_state.os_windows[i].handle == window) {
|
||||
global_state.os_windows[i].render_state = RENDER_FRAME_READY;
|
||||
request_tick_callback();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1082,6 +1099,7 @@ wayland_frame_request_callback(id_type os_window_id) {
|
||||
for (size_t i = 0; i < global_state.num_os_windows; i++) {
|
||||
if (global_state.os_windows[i].id == os_window_id) {
|
||||
global_state.os_windows[i].render_state = RENDER_FRAME_READY;
|
||||
request_tick_callback();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,11 +176,9 @@ void make_os_window_context_current(OSWindow *w);
|
||||
void update_os_window_references();
|
||||
void mark_os_window_for_close(OSWindow* w, bool yes);
|
||||
void update_os_window_viewport(OSWindow *window, bool);
|
||||
void unjam_event_loop();
|
||||
bool should_os_window_close(OSWindow* w);
|
||||
bool should_os_window_be_rendered(OSWindow* w);
|
||||
void wakeup_main_loop();
|
||||
void event_loop_wait(double timeout);
|
||||
void swap_window_buffers(OSWindow *w);
|
||||
void make_window_context_current(OSWindow *w);
|
||||
void hide_mouse(OSWindow *w);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user