From f59c7bbd4303b71c0d20d705edd5dda2b974e7fd Mon Sep 17 00:00:00 2001 From: W2Wizard Date: Sun, 16 Nov 2025 13:03:25 +0100 Subject: [PATCH] Implement python bindings --- .editorconfig | 16 ++ CMakeLists.txt | 24 ++- README.md | 8 + docs/assets/python.png | Bin 0 -> 76932 bytes ffi/python/.gitignore | 216 ++++++++++++++++++++++++++ ffi/python/README.md | 30 ++++ ffi/python/example.py | 89 +++++++++++ ffi/python/libmlx.py | 334 +++++++++++++++++++++++++++++++++++++++++ include/MLX42/MLX42.h | 110 ++++++++------ src/utils/mlx_error.c | 11 +- 10 files changed, 784 insertions(+), 54 deletions(-) create mode 100644 .editorconfig create mode 100644 docs/assets/python.png create mode 100644 ffi/python/.gitignore create mode 100644 ffi/python/README.md create mode 100644 ffi/python/example.py create mode 100644 ffi/python/libmlx.py diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c5c8553 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = false + +[*.{js,jsx,ts,tsx,css,scss,html,svelte,postcss,glsl,c,h}] +indent_size = 2 +indent_style = tab +trim_trailing_whitespace = true \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 144ad3e..a95a436 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,9 +23,11 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON) list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") # Options -set(DEBUG OFF CACHE BOOL "Build MLX42 in debug mode, enabling assertions") -set(GLFW_FETCH ON CACHE BOOL "Clone and install GLFW") -set(BUILD_TESTS OFF CACHE BOOL "Build the tests to verify the integrity of the lib") +# ----------------------------------------------------------------------------- +option(BUILD_SHARED_LIBS "Build mlx42 as a shared library." OFF) +set(DEBUG OFF CACHE BOOL "Build MLX42 in debug mode, enabling assertions") +set(GLFW_FETCH ON CACHE BOOL "Clone and install GLFW") +set(BUILD_TESTS OFF CACHE BOOL "Build the tests to verify the integrity of the lib") # Compile Options # ----------------------------------------------------------------------------- @@ -99,7 +101,9 @@ add_custom_command( # Sources # ----------------------------------------------------------------------------- -add_library(mlx42 STATIC +# The library type is now determined by the BUILD_SHARED_LIBS option. +# By default, it builds a STATIC library. +add_library(mlx42 # Changed from "add_library(mlx42 STATIC" # Root ${SOURCE_DIR}/mlx_cursor.c @@ -134,6 +138,16 @@ add_library(mlx42 STATIC ) target_include_directories(mlx42 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) +# Add this block to control symbol visibility for shared library builds +if(BUILD_SHARED_LIBS) + set_target_properties(mlx42 PROPERTIES + C_VISIBILITY_PRESET hidden + CXX_VISIBILITY_PRESET hidden + ) + target_compile_definitions(mlx42 PRIVATE MLX42_BUILD_SHARED) +endif() + + # Dependencies # ----------------------------------------------------------------------------- @@ -192,4 +206,4 @@ install(TARGETS mlx42 RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" -) +) \ No newline at end of file diff --git a/README.md b/README.md index e183b8d..d50c99d 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,14 @@ You can pass build [options](./docs/index.md#available-options) to cmake, e.g: ` You can find an example makefile in the documentation [here](https://github.com/codam-coding-college/MLX42/blob/master/docs/Basics.md). +#### Bindings (Python, etc) +MLX42 currently has a [Python FFI binding](./ffi/python/README.md) available. +In order to get it working you need to build the library first as shown above. +The only change is that you need to enable the option `BUILD_SHARED_LIBS` when building with cmake: +```bash +cmake -B build -DBUILD_SHARED_LIBS=ON && cmake --build build --parallel +``` + ---- ## For MacOS: diff --git a/docs/assets/python.png b/docs/assets/python.png new file mode 100644 index 0000000000000000000000000000000000000000..219d74a794d97ae4a761f85dd213fbe756e127bf GIT binary patch literal 76932 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ℜ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 t`kbzP@ABO-k!kw>-)4Uc-Mh4~`bQ%l?0 +#+ */ /* +#+ */ /* Created: 2021/12/28 02:29:06 by W2Wizard #+# #+# */ -/* Updated: 2023/03/30 16:23:19 by ntamayo- ######## odam.nl */ +/* Updated: 2025/11/16 13:00:19 by w2wizard ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -32,6 +32,17 @@ # include # include # include + +#if defined(_WIN32) +# if defined(MLX42_BUILD_SHARED) +# define MLX_API __declspec(dllexport) +# else +# define MLX_API __declspec(dllimport) +# endif +#else + #define MLX_API __attribute__((visibility("default"))) +#endif + # ifdef __cplusplus extern "C" { # endif @@ -478,7 +489,14 @@ typedef void mlx_win_cursor_t; * @param[in] val The error code. * @return The error string that describes the error code. */ -const char* mlx_strerror(mlx_errno_t val); +MLX_API const char* mlx_strerror(mlx_errno_t val); + +/** + * Gets the current global error code of MLX. Useful for FFI bindings. + * @example printf("Error: %s\n", mlx_strerror(get_mlx_errno())); + * @return The current global error code. + */ +MLX_API mlx_errno_t mlx_get_errno(void); //= Generic Functions =// @@ -491,7 +509,7 @@ const char* mlx_strerror(mlx_errno_t val); * @param[in] resize Enable window resizing. * @returns Ptr to the MLX handle or null on failure. */ -mlx_t* mlx_init(int32_t width, int32_t height, const char* title, bool resize); +MLX_API mlx_t* mlx_init(int32_t width, int32_t height, const char* title, bool resize); /** * Set a setting for MLX42. @@ -500,7 +518,7 @@ mlx_t* mlx_init(int32_t width, int32_t height, const char* title, bool resize); * @param[in] setting The settings value, See mlx_settings_t type. * @param[in] value Settings value to determine the state of the setting. Can be a boolean or an enum / macro. */ -void mlx_set_setting(mlx_settings_t setting, int32_t value); +MLX_API void mlx_set_setting(mlx_settings_t setting, int32_t value); /** * Notifies MLX that it should stop rendering and exit the main loop. @@ -508,7 +526,7 @@ void mlx_set_setting(mlx_settings_t setting, int32_t value); * * @param[in] mlx The MLX instance handle. */ -void mlx_close_window(mlx_t* mlx); +MLX_API void mlx_close_window(mlx_t* mlx); /** * Initializes the rendering of MLX, this function won't return until @@ -517,7 +535,7 @@ void mlx_close_window(mlx_t* mlx); * * @param[in] mlx The MLX instance handle. */ -void mlx_loop(mlx_t* mlx); +MLX_API void mlx_loop(mlx_t* mlx); /** * Lets you set a custom image as the program icon. @@ -529,7 +547,7 @@ void mlx_loop(mlx_t* mlx); * @param[in] mlx The MLX instance handle. * @param[in] image The image to use as icon. */ -void mlx_set_icon(mlx_t* mlx, mlx_texture_t* image); +MLX_API void mlx_set_icon(mlx_t* mlx, mlx_texture_t* image); /** * Terminates MLX and cleans up any of its used resources. @@ -538,14 +556,14 @@ void mlx_set_icon(mlx_t* mlx, mlx_texture_t* image); * * @param[in] mlx The MLX instance handle. */ -void mlx_terminate(mlx_t* mlx); +MLX_API void mlx_terminate(mlx_t* mlx); /** * Gets the elapsed time since MLX was initialized. * * @return The amount of time elapsed in seconds. */ -double mlx_get_time(void); +MLX_API double mlx_get_time(void); //= Window/Monitor Functions =// @@ -558,7 +576,7 @@ double mlx_get_time(void); * * @param[in] mlx The MLX instance handle. */ -void mlx_focus(mlx_t* mlx); +MLX_API void mlx_focus(mlx_t* mlx); /** * Gets the size of the specified monitor. @@ -567,7 +585,7 @@ void mlx_focus(mlx_t* mlx); * @param[in] width The width of the window. * @param[in] height The height of the window. */ -void mlx_get_monitor_size(int32_t index, int32_t* width, int32_t* height); +MLX_API void mlx_get_monitor_size(int32_t index, int32_t* width, int32_t* height); /** * Sets the window's position. @@ -579,7 +597,7 @@ void mlx_get_monitor_size(int32_t index, int32_t* width, int32_t* height); * @param[in] xpos The x position. * @param[in] ypos The y position. */ -void mlx_set_window_pos(mlx_t* mlx, int32_t xpos, int32_t ypos); +MLX_API void mlx_set_window_pos(mlx_t* mlx, int32_t xpos, int32_t ypos); /** * Gets the window's position. @@ -588,7 +606,7 @@ void mlx_set_window_pos(mlx_t* mlx, int32_t xpos, int32_t ypos); * @param[out] xpos The x position. * @param[out] ypos The y position. */ -void mlx_get_window_pos(mlx_t* mlx, int32_t* xpos, int32_t* ypos); +MLX_API void mlx_get_window_pos(mlx_t* mlx, int32_t* xpos, int32_t* ypos); /** * Changes the window size to the newly specified values. @@ -598,7 +616,7 @@ void mlx_get_window_pos(mlx_t* mlx, int32_t* xpos, int32_t* ypos); * @param[in] new_width The new desired width. * @param[in] new_height The new desired height. */ -void mlx_set_window_size(mlx_t* mlx, int32_t new_width, int32_t new_height); +MLX_API void mlx_set_window_size(mlx_t* mlx, int32_t new_width, int32_t new_height); /** * Sets the size limits of the specified window. @@ -613,7 +631,7 @@ void mlx_set_window_size(mlx_t* mlx, int32_t new_width, int32_t new_height); * @param[in] min_h The min height of the window. * @param[in] max_h The max height of the window. */ -void mlx_set_window_limit(mlx_t* mlx, int32_t min_w, int32_t min_h, int32_t max_w, int32_t max_h); +MLX_API void mlx_set_window_limit(mlx_t* mlx, int32_t min_w, int32_t min_h, int32_t max_w, int32_t max_h); /** * Sets the title of the window. @@ -621,7 +639,7 @@ void mlx_set_window_limit(mlx_t* mlx, int32_t min_w, int32_t min_h, int32_t max_ * @param[in] mlx The MLX instance handle. * @param[in] title The window title. */ -void mlx_set_window_title(mlx_t* mlx, const char* title); +MLX_API void mlx_set_window_title(mlx_t* mlx, const char* title); //= Input Functions =// @@ -632,7 +650,7 @@ void mlx_set_window_title(mlx_t* mlx, const char* title); * @param[in] key The keycode to check, use MLX_KEY_... to specify! * @returns True or false if the key is down or not. */ -bool mlx_is_key_down(mlx_t* mlx, keys_t key); +MLX_API bool mlx_is_key_down(mlx_t* mlx, keys_t key); /** * Checks whether a mouse button is pressed or not. @@ -641,7 +659,7 @@ bool mlx_is_key_down(mlx_t* mlx, keys_t key); * @param[in] key A specific mouse key. e.g MLX_MOUSE_BUTTON_0 * @returns True or false if the mouse key is down or not. */ -bool mlx_is_mouse_down(mlx_t* mlx, mouse_key_t key); +MLX_API bool mlx_is_mouse_down(mlx_t* mlx, mouse_key_t key); /** * Returns the current, relative, mouse cursor position on the window, starting @@ -654,7 +672,7 @@ bool mlx_is_mouse_down(mlx_t* mlx, mouse_key_t key); * @param[out] x The position. * @param[out] y The position. */ -void mlx_get_mouse_pos(mlx_t* mlx, int32_t* x, int32_t* y); +MLX_API void mlx_get_mouse_pos(mlx_t* mlx, int32_t* x, int32_t* y); /** * Sets the mouse position. @@ -662,7 +680,7 @@ void mlx_get_mouse_pos(mlx_t* mlx, int32_t* x, int32_t* y); * @param[in] mlx The MLX instance handle. * @param[in] pos The position. */ -void mlx_set_mouse_pos(mlx_t* mlx, int32_t x, int32_t y); +MLX_API void mlx_set_mouse_pos(mlx_t* mlx, int32_t x, int32_t y); /** * Defines the state for the cursor. @@ -670,7 +688,7 @@ void mlx_set_mouse_pos(mlx_t* mlx, int32_t x, int32_t y); * @param[in] mlx The MLX instance handle. * @param[in] mode A specified mouse mode. */ -void mlx_set_cursor_mode(mlx_t* mlx, mouse_mode_t mode); +MLX_API void mlx_set_cursor_mode(mlx_t* mlx, mouse_mode_t mode); /** * Retrieves the system standard cursor. @@ -678,7 +696,7 @@ void mlx_set_cursor_mode(mlx_t* mlx, mouse_mode_t mode); * @param[in] type The standard cursor type to create. * @return The cursor object or null on failure. */ -mlx_win_cursor_t* mlx_create_std_cursor(cursor_t type); +MLX_API mlx_win_cursor_t* mlx_create_std_cursor(cursor_t type); /** * Allows for the creation of custom cursors with a given texture. @@ -689,14 +707,14 @@ mlx_win_cursor_t* mlx_create_std_cursor(cursor_t type); * @param[in] texture The texture to use as cursor. * @returns The cursor object or null on failure. */ -mlx_win_cursor_t* mlx_create_cursor(mlx_texture_t* texture); +MLX_API mlx_win_cursor_t* mlx_create_cursor(mlx_texture_t* texture); /** * Destroys the given cursor object. * * @param[in] cursor The cursor object to destroy. */ -void mlx_destroy_cursor(mlx_win_cursor_t* cursor); +MLX_API void mlx_destroy_cursor(mlx_win_cursor_t* cursor); /** * Sets the current cursor to the given custom cursor. @@ -704,7 +722,7 @@ void mlx_destroy_cursor(mlx_win_cursor_t* cursor); * @param[in] mlx The MLX instance handle. * @param[in] cursor The cursor object to display, if null default cursor is selected. */ -void mlx_set_cursor(mlx_t* mlx, mlx_win_cursor_t* cursor); +MLX_API void mlx_set_cursor(mlx_t* mlx, mlx_win_cursor_t* cursor); //= Hooks =// @@ -716,7 +734,7 @@ void mlx_set_cursor(mlx_t* mlx, mlx_win_cursor_t* cursor); * @param[in] func The scroll wheel callback function. * @param[in] param An additional optional parameter. */ -void mlx_scroll_hook(mlx_t* mlx, mlx_scrollfunc func, void* param); +MLX_API void mlx_scroll_hook(mlx_t* mlx, mlx_scrollfunc func, void* param); /** * This function sets the mouse callback, which is called when a mouse @@ -726,7 +744,7 @@ void mlx_scroll_hook(mlx_t* mlx, mlx_scrollfunc func, void* param); * @param[in] func The mouse callback function. * @param[in] param An additional optional parameter. */ -void mlx_mouse_hook(mlx_t* mlx, mlx_mousefunc func, void* param); +MLX_API void mlx_mouse_hook(mlx_t* mlx, mlx_mousefunc func, void* param); /** * This function sets the cursor callback, which is called when the @@ -736,7 +754,7 @@ void mlx_mouse_hook(mlx_t* mlx, mlx_mousefunc func, void* param); * @param[in] func The cursor callback function. * @param[in] param An additional optional parameter. */ -void mlx_cursor_hook(mlx_t* mlx, mlx_cursorfunc func, void* param); +MLX_API void mlx_cursor_hook(mlx_t* mlx, mlx_cursorfunc func, void* param); /** * This function sets the key callback, which is called when a key is pressed @@ -746,7 +764,7 @@ void mlx_cursor_hook(mlx_t* mlx, mlx_cursorfunc func, void* param); * @param[in] func The keypress callback function. * @param[in] param An additional optional parameter. */ -void mlx_key_hook(mlx_t* mlx, mlx_keyfunc func, void* param); +MLX_API void mlx_key_hook(mlx_t* mlx, mlx_keyfunc func, void* param); /** * This function sets the close callback, which is called in attempt to close @@ -756,7 +774,7 @@ void mlx_key_hook(mlx_t* mlx, mlx_keyfunc func, void* param); * @param[in] func The close callback function. * @param[in] param An additional optional parameter. */ -void mlx_close_hook(mlx_t* mlx, mlx_closefunc func, void* param); +MLX_API void mlx_close_hook(mlx_t* mlx, mlx_closefunc func, void* param); /** * This function sets the resize callback, which is called when the window is @@ -766,7 +784,7 @@ void mlx_close_hook(mlx_t* mlx, mlx_closefunc func, void* param); * @param[in] func The resize callback function. * @param[in] param An additional optional parameter. */ -void mlx_resize_hook(mlx_t* mlx, mlx_resizefunc func, void* param); +MLX_API void mlx_resize_hook(mlx_t* mlx, mlx_resizefunc func, void* param); /** * Generic loop hook for any custom hooks to add to the main loop. @@ -777,7 +795,7 @@ void mlx_resize_hook(mlx_t* mlx, mlx_resizefunc func, void* param); * @param[in] param The parameter to pass on to the function. * @returns Whether or not the hook was added successfully. */ -bool mlx_loop_hook(mlx_t* mlx, void (*f)(void*), void* param); +MLX_API bool mlx_loop_hook(mlx_t* mlx, void (*f)(void*), void* param); //= Texture Functions =// @@ -787,7 +805,7 @@ bool mlx_loop_hook(mlx_t* mlx, void (*f)(void*), void* param); * @param[in] path Path to the PNG file. * @return If successful the texture data is returned, else NULL. */ -mlx_texture_t* mlx_load_png(const char* path); +MLX_API mlx_texture_t* mlx_load_png(const char* path); /** * Loads an XPM42 texture from the given file path. @@ -795,14 +813,14 @@ mlx_texture_t* mlx_load_png(const char* path); * @param[in] path The file path to the XPM texture. * @returns The XPM texture struct containing its information. */ -xpm_t* mlx_load_xpm42(const char* path); +MLX_API xpm_t* mlx_load_xpm42(const char* path); /** * Deletes a texture by freeing its allocated data. * * @param[in] texture The texture to free. */ -void mlx_delete_texture(mlx_texture_t* texture); +MLX_API void mlx_delete_texture(mlx_texture_t* texture); /** * Deletes an XPM42 texture by freeing its allocated data. @@ -812,7 +830,7 @@ void mlx_delete_texture(mlx_texture_t* texture); * * @param[in] xpm The xpm texture to delete. */ -void mlx_delete_xpm42(xpm_t* xpm); +MLX_API void mlx_delete_xpm42(xpm_t* xpm); /** * Converts a given texture to an image. @@ -821,7 +839,7 @@ void mlx_delete_xpm42(xpm_t* xpm); * @param[in] texture The texture to use to create the image from. * @return mlx_image_t* The image created from the texture. */ -mlx_image_t* mlx_texture_to_image(mlx_t* mlx, mlx_texture_t* texture); +MLX_API mlx_image_t* mlx_texture_to_image(mlx_t* mlx, mlx_texture_t* texture); //= Image Functions =// @@ -836,7 +854,7 @@ mlx_image_t* mlx_texture_to_image(mlx_t* mlx, mlx_texture_t* texture); * @param[in] y The Y coordinate position. * @param[in] color The color value to put. */ -void mlx_put_pixel(mlx_image_t* image, uint32_t x, uint32_t y, uint32_t color); +MLX_API void mlx_put_pixel(mlx_image_t* image, uint32_t x, uint32_t y, uint32_t color); /** * Creates and allocates a new image buffer. @@ -846,7 +864,7 @@ void mlx_put_pixel(mlx_image_t* image, uint32_t x, uint32_t y, uint32_t color); * @param[in] height The desired height of the image. * @return Pointer to the image buffer, if it failed to allocate then NULL. */ -mlx_image_t* mlx_new_image(mlx_t* mlx, uint32_t width, uint32_t height); +MLX_API mlx_image_t* mlx_new_image(mlx_t* mlx, uint32_t width, uint32_t height); /** * Draws a new instance of an image, it will then share the same @@ -865,7 +883,7 @@ mlx_image_t* mlx_new_image(mlx_t* mlx, uint32_t width, uint32_t height); * @param[in] y The Y position. * @return Index to the instance, or -1 on failure. */ -int32_t mlx_image_to_window(mlx_t* mlx, mlx_image_t* img, int32_t x, int32_t y); +MLX_API int32_t mlx_image_to_window(mlx_t* mlx, mlx_image_t* img, int32_t x, int32_t y); /** * Deleting an image will remove it from the render queue as well as any and all @@ -878,7 +896,7 @@ int32_t mlx_image_to_window(mlx_t* mlx, mlx_image_t* img, int32_t x, int32_t y); * @param[in] mlx The MLX instance handle. * @param[in] image The image to delete. */ -void mlx_delete_image(mlx_t* mlx, mlx_image_t* image); +MLX_API void mlx_delete_image(mlx_t* mlx, mlx_image_t* image); /** * Allows you to resize an image, a new pixel buffer is allocated @@ -889,7 +907,7 @@ void mlx_delete_image(mlx_t* mlx, mlx_image_t* image); * @param[in] nheight The new height. * @return True if image was resized or false on error. */ -bool mlx_resize_image(mlx_image_t* img, uint32_t nwidth, uint32_t nheight); +MLX_API bool mlx_resize_image(mlx_image_t* img, uint32_t nwidth, uint32_t nheight); /** * Sets the depth / Z axis value of an instance. @@ -901,7 +919,7 @@ bool mlx_resize_image(mlx_image_t* img, uint32_t nwidth, uint32_t nheight); * @param[in] instance The instance on which to change the depth. * @param[in] zdepth The new depth value. */ -void mlx_set_instance_depth(mlx_instance_t* instance, int32_t zdepth); +MLX_API void mlx_set_instance_depth(mlx_instance_t* instance, int32_t zdepth); //= String Functions =// @@ -914,14 +932,14 @@ void mlx_set_instance_depth(mlx_instance_t* instance, int32_t zdepth); * @param[in] y The Y location. * @return Image ptr to the string. */ -mlx_image_t* mlx_put_string(mlx_t* mlx, const char* str, int32_t x, int32_t y); +MLX_API mlx_image_t* mlx_put_string(mlx_t* mlx, const char* str, int32_t x, int32_t y); /** * Retrieve the texture data for the built-in font. * * @return Pointer to the built-in font texture. */ -const mlx_texture_t* mlx_get_font(void); +MLX_API const mlx_texture_t* mlx_get_font(void); /** * This function lets you retrieve the X offset @@ -932,7 +950,7 @@ const mlx_texture_t* mlx_get_font(void); * @param[in] c The character to get the offset from. * @return Non-negative if found or -1 if not found. */ -int32_t mlx_get_texoffset(char c); +MLX_API int32_t mlx_get_texoffset(char c); # ifdef __cplusplus } diff --git a/src/utils/mlx_error.c b/src/utils/mlx_error.c index 1a9f867..cc36b5c 100644 --- a/src/utils/mlx_error.c +++ b/src/utils/mlx_error.c @@ -6,7 +6,7 @@ /* By: W2Wizard +#+ */ /* +#+ */ /* Created: 2021/12/28 02:51:54 by W2Wizard #+# #+# */ -/* Updated: 2022/11/22 08:50:15 by jvan-hal ######## odam.nl */ +/* Updated: 2025/11/16 13:00:50 by w2wizard ######## odam.nl */ /* */ /* ************************************************************************** */ @@ -36,9 +36,9 @@ static const char* mlx_errors[MLX_ERRMAX] = { /** * Functions to set the error number, simply for convenience. - * + * * @param val The error value. - * @return Always false + * @return Always false */ bool mlx_error(mlx_errno_t val) { @@ -58,3 +58,8 @@ const char* mlx_strerror(mlx_errno_t val) return (mlx_errors[val]); } + +mlx_errno_t mlx_get_errno(void) +{ + return (mlx_errno); +} \ No newline at end of file