diff --git a/kitty/cleanup.c b/kitty/cleanup.c new file mode 100644 index 000000000..6f15fc21c --- /dev/null +++ b/kitty/cleanup.c @@ -0,0 +1,23 @@ +/* + * cleanup.c + * Copyright (C) 2021 Kovid Goyal + * + * Distributed under terms of the GPL3 license. + */ + +#include "cleanup.h" + + +kitty_cleanup_at_exit_func exit_funcs[NUM_CLEANUP_FUNCS] = {0}; + +void +register_at_exit_cleanup_func(AtExitCleanupFunc which, kitty_cleanup_at_exit_func func) { + if (which < NUM_CLEANUP_FUNCS) exit_funcs[which] = func; +} + +void +run_at_exit_cleanup_functions(void) { + for (unsigned i = 0; i < NUM_CLEANUP_FUNCS; i++) { + if (exit_funcs[i]) exit_funcs[i](); + } +} diff --git a/kitty/cleanup.h b/kitty/cleanup.h new file mode 100644 index 000000000..e39bde86c --- /dev/null +++ b/kitty/cleanup.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2021 Kovid Goyal + * + * Distributed under terms of the GPL3 license. + */ + +#pragma once + +typedef void (*kitty_cleanup_at_exit_func)(void); + +typedef enum { + STATE_CLEANUP_FUNC, + GLFW_CLEANUP_FUNC, + DESKTOP_CLEANUP_FUNC, + FREETYPE_CLEANUP_FUNC, + CORE_TEXT_CLEANUP_FUNC, + COCOA_CLEANUP_FUNC, + PNG_READER_CLEANUP_FUNC, + FONTCONFIG_CLEANUP_FUNC, + + NUM_CLEANUP_FUNCS +} AtExitCleanupFunc; + +void register_at_exit_cleanup_func(AtExitCleanupFunc which, kitty_cleanup_at_exit_func func); +void run_at_exit_cleanup_functions(void); diff --git a/kitty/cocoa_window.m b/kitty/cocoa_window.m index 6aa1888dd..4c2bde9cf 100644 --- a/kitty/cocoa_window.m +++ b/kitty/cocoa_window.m @@ -7,6 +7,7 @@ #include "state.h" +#include "cleanup.h" #include "monotonic.h" #include #ifndef KITTY_USE_DEPRECATED_MACOS_NOTIFICATION_API @@ -656,9 +657,6 @@ bool init_cocoa(PyObject *module) { memset(&global_shortcuts, 0, sizeof(global_shortcuts)); if (PyModule_AddFunctions(module, module_methods) != 0) return false; - if (Py_AtExit(cleanup) != 0) { - PyErr_SetString(PyExc_RuntimeError, "Failed to register the cocoa_window at exit handler"); - return false; - } + register_at_exit_cleanup_func(COCOA_CLEANUP_FUNC, cleanup); return true; } diff --git a/kitty/core_text.m b/kitty/core_text.m index b27284f82..b3065f621 100644 --- a/kitty/core_text.m +++ b/kitty/core_text.m @@ -6,6 +6,7 @@ */ #include "state.h" +#include "cleanup.h" #include "fonts.h" #include "unicode-data.h" #include @@ -608,10 +609,7 @@ init_CoreText(PyObject *module) { if (PyType_Ready(&CTFace_Type) < 0) return 0; if (PyModule_AddObject(module, "CTFace", (PyObject *)&CTFace_Type) != 0) return 0; if (PyModule_AddFunctions(module, module_methods) != 0) return 0; - if (Py_AtExit(finalize) != 0) { - PyErr_SetString(PyExc_RuntimeError, "Failed to register the CoreText at exit handler"); - return false; - } + register_at_exit_cleanup_func(CORE_TEXT_CLEANUP_FUNC, finalize); return 1; } diff --git a/kitty/data-types.c b/kitty/data-types.c index 2e7f4ae92..498411099 100644 --- a/kitty/data-types.c +++ b/kitty/data-types.c @@ -12,6 +12,7 @@ #undef _DARWIN_C_SOURCE #endif #include "data-types.h" +#include "cleanup.h" #include "safe-wrappers.h" #include "control-codes.h" #include "wcwidth-std.h" @@ -226,6 +227,10 @@ PyInit_fast_data_types(void) { m = PyModule_Create(&module); if (m == NULL) return NULL; + if (Py_AtExit(run_at_exit_cleanup_functions) != 0) { + PyErr_SetString(PyExc_RuntimeError, "Failed to register the atexit cleanup handler"); + return NULL; + } init_monotonic(); if (!init_logging(m)) return NULL; @@ -237,6 +242,7 @@ PyInit_fast_data_types(void) { if (!init_child_monitor(m)) return NULL; if (!init_ColorProfile(m)) return NULL; if (!init_Screen(m)) return NULL; + if (!init_glfw(m)) return NULL; if (!init_child(m)) return NULL; if (!init_state(m)) return NULL; if (!init_keys(m)) return NULL; @@ -256,7 +262,6 @@ PyInit_fast_data_types(void) { if (!init_freetype_render_ui_text(m)) return NULL; #endif if (!init_fonts(m)) return NULL; - if (!init_glfw(m)) return NULL; PyModule_AddIntConstant(m, "BOLD", BOLD_SHIFT); PyModule_AddIntConstant(m, "ITALIC", ITALIC_SHIFT); diff --git a/kitty/desktop.c b/kitty/desktop.c index b3d5625a2..9fea4bfa0 100644 --- a/kitty/desktop.c +++ b/kitty/desktop.c @@ -6,6 +6,7 @@ */ #include "data-types.h" +#include "cleanup.h" #include #define FUNC(name, restype, ...) typedef restype (*name##_func)(__VA_ARGS__); static name##_func name = NULL @@ -174,9 +175,6 @@ finalize(void) { bool init_desktop(PyObject *m) { if (PyModule_AddFunctions(m, module_methods) != 0) return false; - if (Py_AtExit(finalize) != 0) { - PyErr_SetString(PyExc_RuntimeError, "Failed to register the desktop.c at exit handler"); - return false; - } + register_at_exit_cleanup_func(DESKTOP_CLEANUP_FUNC, finalize); return true; } diff --git a/kitty/fontconfig.c b/kitty/fontconfig.c index a5ccf68b0..3826f820c 100644 --- a/kitty/fontconfig.c +++ b/kitty/fontconfig.c @@ -6,6 +6,7 @@ */ #include "state.h" +#include "cleanup.h" #include "lineops.h" #include "fonts.h" #include @@ -339,10 +340,7 @@ init_fontconfig_library(PyObject *module) { PyErr_SetString(PyExc_RuntimeError, "Failed to initialize the fontconfig library"); return false; } - if (Py_AtExit(FcFini) != 0) { - PyErr_SetString(PyExc_RuntimeError, "Failed to register the fontconfig library at exit handler"); - return false; - } + register_at_exit_cleanup_func(FONTCONFIG_CLEANUP_FUNC, FcFini); if (PyModule_AddFunctions(module, module_methods) != 0) return false; PyModule_AddIntMacro(module, FC_WEIGHT_REGULAR); PyModule_AddIntMacro(module, FC_WEIGHT_MEDIUM); diff --git a/kitty/freetype.c b/kitty/freetype.c index d7b47531b..260f8ce6c 100644 --- a/kitty/freetype.c +++ b/kitty/freetype.c @@ -6,6 +6,7 @@ */ #include "fonts.h" +#include "cleanup.h" #include "state.h" #include #include @@ -737,10 +738,7 @@ init_freetype_library(PyObject *m) { set_freetype_error("Failed to initialize FreeType library, with error:", error); return false; } - if (Py_AtExit(free_freetype) != 0) { - PyErr_SetString(FreeType_Exception, "Failed to register the freetype library at exit handler"); - return false; - } + register_at_exit_cleanup_func(FREETYPE_CLEANUP_FUNC, free_freetype); return true; } diff --git a/kitty/glfw.c b/kitty/glfw.c index 4d2587149..7ec46f6ac 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -5,6 +5,7 @@ */ #include "state.h" +#include "cleanup.h" #include "fonts.h" #include "monotonic.h" #include "charsets.h" @@ -1426,10 +1427,7 @@ void cleanup_glfw(void) { bool init_glfw(PyObject *m) { if (PyModule_AddFunctions(m, module_methods) != 0) return false; - if (Py_AtExit(cleanup_glfw) != 0) { - PyErr_SetString(PyExc_RuntimeError, "Failed to register the glfw exit handler"); - return false; - } + register_at_exit_cleanup_func(GLFW_CLEANUP_FUNC, cleanup_glfw); #define ADDC(n) if(PyModule_AddIntConstant(m, #n, n) != 0) return false; ADDC(GLFW_RELEASE); ADDC(GLFW_PRESS); diff --git a/kitty/png-reader.c b/kitty/png-reader.c index 9bfaf6cfc..13bf7db6b 100644 --- a/kitty/png-reader.c +++ b/kitty/png-reader.c @@ -6,6 +6,7 @@ */ #include "png-reader.h" +#include "cleanup.h" #include "state.h" #include @@ -167,10 +168,6 @@ unload(void) { bool init_png_reader(PyObject *module) { if (PyModule_AddFunctions(module, module_methods) != 0) return false; - if (Py_AtExit(unload) != 0) { - PyErr_SetString(PyExc_RuntimeError, "Failed to register the PNG library at exit handler"); - return false; - } - + register_at_exit_cleanup_func(PNG_READER_CLEANUP_FUNC, unload); return true; } diff --git a/kitty/state.c b/kitty/state.c index 97c56ba95..8d7800ee0 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -6,6 +6,7 @@ */ #include "state.h" +#include "cleanup.h" #include GlobalState global_state = {{0}}; @@ -1251,10 +1252,7 @@ init_state(PyObject *module) { PyModule_AddIntConstant(module, "IMPERATIVE_CLOSE_REQUESTED", IMPERATIVE_CLOSE_REQUESTED); PyModule_AddIntConstant(module, "NO_CLOSE_REQUESTED", NO_CLOSE_REQUESTED); PyModule_AddIntConstant(module, "CLOSE_BEING_CONFIRMED", CLOSE_BEING_CONFIRMED); - if (Py_AtExit(finalize) != 0) { - PyErr_SetString(PyExc_RuntimeError, "Failed to register the state at exit handler"); - return false; - } + register_at_exit_cleanup_func(STATE_CLEANUP_FUNC, finalize); return true; } // }}}