diff --git a/kitty/cleanup.c b/kitty/cleanup.c index 6f15fc21c..03298501a 100644 --- a/kitty/cleanup.c +++ b/kitty/cleanup.c @@ -6,6 +6,7 @@ */ #include "cleanup.h" +#include kitty_cleanup_at_exit_func exit_funcs[NUM_CLEANUP_FUNCS] = {0}; @@ -19,5 +20,6 @@ void run_at_exit_cleanup_functions(void) { for (unsigned i = 0; i < NUM_CLEANUP_FUNCS; i++) { if (exit_funcs[i]) exit_funcs[i](); + exit_funcs[i] = NULL; } } diff --git a/kitty/data-types.c b/kitty/data-types.c index 3805b3150..bdd2378a2 100644 --- a/kitty/data-types.c +++ b/kitty/data-types.c @@ -605,6 +605,11 @@ py_timed_debug_print(PyObject *self UNUSED, PyObject *args) { Py_RETURN_NONE; } +static PyObject* +py_run_atexit_cleanup_functions(PyObject *self UNUSED, PyObject *args UNUSED) { + run_at_exit_cleanup_functions(); + Py_RETURN_NONE; +} static PyMethodDef module_methods[] = { METHODB(replace_c0_codes_except_nl_space_tab, METH_O), @@ -632,6 +637,7 @@ static PyMethodDef module_methods[] = { {"monotonic", (PyCFunction)py_monotonic, METH_NOARGS, ""}, {"timed_debug_print", (PyCFunction)py_timed_debug_print, METH_VARARGS, ""}, {"find_in_memoryview", (PyCFunction)find_in_memoryview, METH_VARARGS, ""}, + {"run_at_exit_cleanup_functions", (PyCFunction)py_run_atexit_cleanup_functions, METH_NOARGS, ""}, #ifdef __APPLE__ METHODB(user_cache_dir, METH_NOARGS), METHODB(process_group_map, METH_NOARGS), diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index d7155714f..80d50383e 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -1723,6 +1723,7 @@ def set_redirect_keys_to_overlay(os_window_id: int, tab_id: int, window_id: int, def buffer_keys_in_window(os_window_id: int, tab_id: int, window_id: int, enabled: bool = True) -> bool: ... def sprite_idx_to_pos(idx: int, xnum: int, ynum: int) -> tuple[int, int, int]: ... def render_box_char(ch: int, width: int, height: int, scale: float = 1.0, dpi_x: float = 96.0, dpi_y: float = 96.0) -> bytes: ... +def run_at_exit_cleanup_functions() -> None: ... class MousePosition(TypedDict): cell_x: int diff --git a/kitty/launcher/main.c b/kitty/launcher/main.c index 133ce76e8..b6c7d3005 100644 --- a/kitty/launcher/main.c +++ b/kitty/launcher/main.c @@ -466,5 +466,6 @@ int main(int argc, char *argv[], char* envp[]) { RunData run_data = {.exe = exe, .exe_dir = exe_dir, .lib_dir = lib, .argc = argc, .argv = argv, .lc_ctype = lc_ctype}; ret = run_embedded(&run_data); single_instance_main(-1, NULL, NULL); + Py_FinalizeEx(); return ret; } diff --git a/kitty/main.py b/kitty/main.py index 83e2f2f4e..ca6045a4e 100644 --- a/kitty/main.py +++ b/kitty/main.py @@ -40,6 +40,7 @@ from .fast_data_types import ( glfw_terminate, load_png_data, mask_kitty_signals_process_wide, + run_at_exit_cleanup_functions, set_custom_cursor, set_default_window_icon, set_options, @@ -537,3 +538,7 @@ def main() -> None: tb = traceback.format_exc() log_error(tb) raise SystemExit(1) + finally: + # we cant rely on this running during module unloading of fast_data_types as Python fails + # to unload the module, due to reference cycles, I am guessing. + run_at_exit_cleanup_functions()