Files
amazing/mlx/mlx.py
T
2026-03-25 17:40:13 +01:00

269 lines
12 KiB
Python

# MLX python wrapper for Mlx C library
# See mlx manuals and mlx.h from C library for function usage
# C Functions that require addresses to pass back info are converted to
# Pythod methods that return a tuple
from ctypes import *
import os
class Mlx:
def __init__(self):
module_dir = os.path.dirname(os.path.abspath(__file__))
self.so_file = os.path.join(module_dir, "libmlx.so")
self.mlx_func = CDLL(self.so_file)
self._python_ref_std = {}
self._python_ref_gen = {}
self._img_height = {}
# Initialisation
def mlx_init(self):
self.mlx_func.mlx_init.restype = c_void_p
return self.mlx_func.mlx_init()
def mlx_release(self, mlx_ptr):
self.mlx_func.mlx_release.argtypes = [c_void_p]
self.mlx_func.mlx_release.restypes = [c_int]
return self.mlx_func.mlx_release(mlx_ptr)
# Windows
def mlx_new_window(self, mlx_ptr, width, height, title):
self.mlx_func.mlx_new_window.argtypes = [c_void_p, c_uint, c_uint, c_char_p]
self.mlx_func.mlx_new_window.restype = c_void_p
return self.mlx_func.mlx_new_window(mlx_ptr, width, height, title.encode('utf-8'))
def mlx_clear_window(self, mlx_ptr, win_ptr):
self.mlx_func.mlx_clear_window.argtypes = [c_void_p, c_void_p]
self.mlx_func.mlx_clear_window.restype = c_int
return self.mlx_func.mlx_clear_window(mlx_ptr, win_ptr)
def mlx_pixel_put(self, mlx_ptr, win_ptr, x, y, color):
self.mlx_func.mlx_pixel_put.argtypes = [c_void_p, c_void_p, c_uint, c_uint, c_uint]
self.mlx_func.mlx_pixel_put.restype = c_int
return self.mlx_func.mlx_pixel_put(mlx_ptr, win_ptr, x, y, color)
def mlx_destroy_window(self, mlx_ptr, win_ptr):
self.mlx_func.mlx_destroy_window.argtypes = [c_void_p, c_void_p]
self.mlx_func.mlx_destroy_window.restype = c_int
return self.mlx_func.mlx_destroy_window(mlx_ptr, win_ptr)
# Images
def mlx_new_image(self, mlx_ptr, width, height):
self.mlx_func.mlx_new_image.argtypes = [c_void_p, c_uint, c_uint]
self.mlx_func.mlx_new_image.restype = c_void_p
ret = self.mlx_func.mlx_new_image(mlx_ptr, width, height)
if ret is not None:
self._img_height[str(ret)] = height
return ret
# API break, returns tuple
def mlx_get_data_addr(self, img_ptr):
bits_per_pixel = c_uint()
size_line = c_uint()
theformat = c_uint()
data = POINTER(c_char)
self.mlx_func.mlx_get_data_addr.argtypes = [c_void_p, POINTER(c_uint), POINTER(c_uint), POINTER(c_uint)]
self.mlx_func.mlx_get_data_addr.restype = POINTER(c_char)
data = self.mlx_func.mlx_get_data_addr(img_ptr, byref(bits_per_pixel), byref(size_line), byref(theformat))
data_array = c_char * (self._img_height[str(img_ptr)] * size_line.value)
data_view = data_array.from_address(addressof(data.contents))
return (memoryview(data_view).cast('B'), bits_per_pixel.value, size_line.value, theformat.value)
def mlx_put_image_to_window(self, mlx_ptr, win_ptr, img_ptr, x, y):
self.mlx_func.mlx_put_image_to_window.argtypes = [c_void_p, c_void_p, c_void_p, c_int, c_int]
self.mlx_func.mlx_put_image_to_window.restype = c_int
return self.mlx_func.mlx_put_image_to_window(mlx_ptr, win_ptr, img_ptr, x, y)
def mlx_destroy_image(self, mlx_ptr, img_ptr):
self._img_height.pop(str(img_ptr))
self.mlx_func.mlx_destroy_image.argtypes = [c_void_p, c_void_p]
self.mlx_func.mlx_destroy_image.restype = c_int
return self.mlx_func.mlx_destroy_image(mlx_ptr, img_ptr)
# Events & main loop
# Note: Python can't catch C^-C from keyboard during mlx_loop execution.
# Use C^-\ to kill your program.
def mlx_loop(self, mlx_ptr):
self.mlx_func.mlx_loop.argtypes = [c_void_p]
self.mlx_func.mlx_loop.restype = c_int
return self.mlx_func.mlx_loop(mlx_ptr)
def mlx_loop_exit(self, mlx_ptr):
self.mlx_func.mlx_loop_exit.argtypes = [c_void_p]
self.mlx_func.mlx_loop_exit.restype = c_int
return self.mlx_func.mlx_loop_exit(mlx_ptr)
def mlx_mouse_hook(self, win_ptr, callback, param):
self.mlx_func.mlx_mouse_hook.restype = c_int
if not callback:
self._python_ref_std[str(win_ptr)+"_mouse_f"] = None
self._python_ref_std[str(win_ptr)+"_mouse_p"] = None
self.mlx_func.mlx_mouse_hook.argtypes = [c_void_p, c_void_p, c_void_p]
return self.mlx_func.mlx_mouse_hook(win_ptr, None, None)
callback_type = CFUNCTYPE(None, c_uint, c_uint, c_uint, py_object)
self.mlx_func.mlx_mouse_hook.argtypes = [c_void_p, callback_type, py_object]
callback_ref = callback_type(callback)
self._python_ref_std[str(win_ptr)+"_mouse_f"] = callback_ref
self._python_ref_std[str(win_ptr)+"_mouse_p"] = param
return self.mlx_func.mlx_mouse_hook(win_ptr, callback_ref, param)
def mlx_key_hook(self, win_ptr, callback, param):
self.mlx_func.mlx_key_hook.restype = c_int
if not callback:
self._python_ref_std[str(win_ptr)+"_key_f"] = None
self._python_ref_std[str(win_ptr)+"_key_p"] = None
self.mlx_func.mlx_key_hook.argtypes = [c_void_p, c_void_p, c_void_p]
return self.mlx_func.mlx_key_hook(win_ptr, None, None)
callback_type = CFUNCTYPE(None, c_uint, py_object)
self.mlx_func.mlx_key_hook.argtypes = [c_void_p, callback_type, py_object]
callback_ref = callback_type(callback)
self._python_ref_std[str(win_ptr)+"_key_f"] = callback_ref
self._python_ref_std[str(win_ptr)+"_key_p"] = param
return self.mlx_func.mlx_key_hook(win_ptr, callback_ref, param)
def mlx_expose_hook(self, win_ptr, callback, param):
self.mlx_func.mlx_expose_hook.restype = c_int
if not callback:
self._python_ref_std[str(win_ptr)+"_expose_f"] = None
self._python_ref_std[str(win_ptr)+"_expose_p"] = None
self.mlx_func.mlx_expose_hook.argtypes = [c_void_p, c_void_p, c_void_p]
return self.mlx_func.mlx_expose_hook(win_ptr, None, None)
callback_type = CFUNCTYPE(None, py_object)
self.mlx_func.mlx_expose_hook.argtypes = [c_void_p, callback_type, py_object]
callback_ref = callback_type(callback)
self._python_ref_std[str(win_ptr)+"_expose_f"] = callback_ref
self._python_ref_std[str(win_ptr)+"_expose_p"] = param
return self.mlx_func.mlx_expose_hook(win_ptr, callback_ref, param)
def mlx_loop_hook(self, mlx_ptr, callback, param):
self.mlx_func.mlx_loop_hook.restype = c_int
if not callback:
self._python_ref_std["loop_f"] = None
self._python_ref_std["loop_p"] = None
self.mlx_func.mlx_loop_hook.argtypes = [c_void_p, c_void_p, c_void_p]
return self.mlx_func.mlx_loop_hook(mlx_ptr, None, None)
callback_type = CFUNCTYPE(None, py_object)
self.mlx_func.mlx_loop_hook.argtypes = [c_void_p, callback_type, py_object]
callback_ref = callback_type(callback)
self._python_ref_std["loop_f"] = callback_ref
self._python_ref_std["loop_p"] = param
return self.mlx_func.mlx_loop_hook(mlx_ptr, callback_ref, param)
def mlx_hook(self, win_ptr, x_event, x_mask, callback, param):
x_event_key = [2, 3]
x_event_mouse = [4, 5]
x_event_motion = [6]
self.mlx_func.mlx_hook.restype = c_int
if not callback:
self._python_ref_gen[str(win_ptr)+"_f_"+str(x_event)] = None
self._python_ref_gen[str(win_ptr)+"_p_"+str(x_event)] = None
self.mlx_func.mlx_hook.argtypes = [c_void_p, c_uint, c_uint, c_void_p, c_void_p]
return self.mlx_func.mlx_hook(win_ptr, 0, 0, None, None)
if x_event in x_event_key:
callback_type = CFUNCTYPE(None, c_uint, py_object)
elif x_event in x_event_mouse:
callback_type = CFUNCTYPE(None, c_uint, c_uint, c_uint, py_object)
elif x_event in x_event_motion:
callback_type = CFUNCTYPE(None, c_uint, c_uint, py_object)
else:
callback_type = CFUNCTYPE(None, py_object)
self.mlx_func.mlx_hook.argtypes = [c_void_p, c_uint, c_uint, callback_type, py_object]
callback_ref = callback_type(callback)
self._python_ref_gen[str(win_ptr)+"_f_"+str(x_event)] = callback_ref
self._python_ref_gen[str(win_ptr)+"_p_"+str(x_event)] = param
return self.mlx_func.mlx_hook(win_ptr, x_event, x_mask, callback_ref, param)
# Misc.
def mlx_string_put(self, mlx_ptr, win_ptr, x, y, color, string):
self.mlx_func.mlx_string_put.argtypes = [c_void_p, c_void_p, c_uint, c_uint, c_uint, c_char_p]
self.mlx_func.mlx_string_put.restype = c_int
return self.mlx_func.mlx_string_put(mlx_ptr, win_ptr, x, y, color, string.encode('utf-8'))
# API break, returns tuple
def mlx_xpm_file_to_image(self, mlx_ptr, filename):
width = c_uint()
height = c_uint()
self.mlx_func.mlx_xpm_file_to_image.argtypes = [c_void_p, c_char_p, c_void_p, c_void_p]
self.mlx_func.mlx_xpm_file_to_image.restype = c_void_p
img = self.mlx_func.mlx_xpm_file_to_image(mlx_ptr, filename.encode('utf8'), byref(width), byref(height))
if img is not None:
self._img_height[str(img)] = height.value
return (img, width.value, height.value)
# API break, returns tuple
def mlx_png_file_to_image(self, mlx_ptr, filename):
width = c_uint()
height = c_uint()
self.mlx_func.mlx_png_file_to_image.argtypes = [c_void_p, c_char_p, c_void_p, c_void_p]
self.mlx_func.mlx_png_file_to_image.restype = c_void_p
img = self.mlx_func.mlx_png_file_to_image(mlx_ptr, filename.encode('utf8'), byref(width), byref(height))
if img is not None:
self._img_height[str(img)] = height.value
return (img, width.value, height.value)
# not really usefull in Python context
#void *mlx_xpm_to_image(void *mlx_ptr, const char **xpm_data,
# unsigned int *width, unsigned int *height);
def mlx_mouse_hide(self, mlx_ptr):
self.mlx_func.mlx_mouse_hide.argtypes = [c_void_p]
self.mlx_func.mlx_mouse_hide.restype = c_int
return self.mlx_func.mlx_mouse_hide(mlx_ptr)
def mlx_mouse_show(self, mlx_ptr):
self.mlx_func.mlx_mouse_show.argtypes = [c_void_p]
self.mlx_func.mlx_mouse_show.restype = c_int
return self.mlx_func.mlx_mouse_show(mlx_ptr)
def mlx_mouse_move(self, mlx_ptr, x, y):
self.mlx_func.mlx_mouse_move.argtypes = [c_void_p, c_int, c_int]
self.mlx_func.mlx_mouse_move.restype = c_int
return self.mlx_func.mlx_mouse_move(mlx_ptr, x, y)
# API break, returns tuple
def mlx_mouse_get_pos(self, mlx_ptr):
x = c_int()
y = c_int()
self.mlx_func.mlx_mouse_get_pos.argtypes = [c_void_p, c_void_p, c_void_p]
self.mlx_func.mlx_mouse_get_pos.restype = c_int
val = self.mlx_func.mlx_mouse_get_pos(mlx_ptr, byref(x), byref(y))
return (val, x.value, y.value)
def mlx_do_key_autorepeatoff(self, mlx_ptr):
self.mlx_func.mlx_do_key_autorepeatoff.argtypes = [c_void_p]
self.mlx_func.mlx_do_key_autorepeatoff.restype = c_int
return self.mlx_func.mlx_do_key_autorepeatoff(mlx_ptr)
def mlx_do_key_autorepeaton(self, mlx_ptr):
self.mlx_func.mlx_do_key_autorepeaton.argtypes = [c_void_p]
self.mlx_func.mlx_do_key_autorepeaton.restype = c_int
return self.mlx_func.mlx_do_key_autorepeaton(mlx_ptr)
# API break, returns tuple
def mlx_get_screen_size(self, mlx_ptr):
w = c_uint()
h = c_uint()
self.mlx_func.mlx_get_screen_size.argtypes = [c_void_p, POINTER(c_uint), POINTER(c_uint)]
self.mlx_func.mlx_get_screen_size.restype = c_int
val = self.mlx_func.mlx_get_screen_size(mlx_ptr, byref(w), byref(h))
return (val, w.value, h.value)
# Sync funct
def mlx_do_sync(self, mlx_ptr):
self.mlx_func.mlx_do_sync.argtypes = [c_void_p]
self.mlx_func.mlx_do_sync.restype = c_int
return self.mlx_func.mlx_do_sync(mlx_ptr)
def mlx_sync(self, mlx_ptr, cmd, img_or_win_ptr):
self.mlx_func.mlx_sync.argtypes = [c_void_p, c_int, c_void_p]
self.mlx_func.mlx_sync.restype = c_int
return self.mlx_func.mlx_sync(mlx_ptr, cmd, img_or_win_ptr)
SYNC_IMAGE_WRITABLE = 1
SYNC_WIN_FLUSH = 2
SYNC_WIN_COMPLETED = 3