miniquad 0.4.10

Cross-platform window context and rendering library.
Documentation
use super::libwayland_client::{
    wl_buffer, wl_proxy, wl_shm, wl_shm_format_WL_SHM_FORMAT_ARGB8888, wl_shm_pool,
    LibWaylandClient, WL_SHM_CREATE_POOL, WL_SHM_POOL_CREATE_BUFFER, WL_SHM_POOL_DESTROY,
};
use crate::wl_request_constructor;

unsafe fn wl_shm_pool_destroy(libwayland: &mut LibWaylandClient, wl_shm_pool: *mut wl_shm_pool) {
    (libwayland.wl_proxy_marshal)(wl_shm_pool as _, WL_SHM_POOL_DESTROY);
    (libwayland.wl_proxy_destroy)(wl_shm_pool as _);
}

unsafe extern "C" fn create_tmpfile_cloexec(tmpname: *mut libc::c_char) -> libc::c_int {
    let fd = libc::mkostemp(tmpname, libc::O_CLOEXEC);
    if fd >= 0 {
        libc::unlink(tmpname);
    }
    fd
}

unsafe extern "C" fn create_anonymous_file(size: usize) -> libc::c_int {
    let xdg_folder_path = std::env::var("XDG_RUNTIME_DIR").expect("XDG_RUNTIME_DIR not set");
    let filepath = format!("{}/miniquad-shared-XXXXXX", xdg_folder_path);
    let c_filepath = std::ffi::CString::new(filepath).unwrap();
    let fd = create_tmpfile_cloexec(c_filepath.as_ptr() as _);

    if fd < 0 {
        panic!("Cant create temp file");
    }

    let ret = libc::posix_fallocate(fd, 0, size as _);

    if ret != 0 {
        libc::close(fd);
        panic!("Cant create temp file")
    }
    fd
}

pub unsafe fn create_shm_buffer(
    libwayland: &mut LibWaylandClient,
    shm: *mut wl_shm,
    width: i32,
    height: i32,
    pixels: &[u8],
) -> *mut wl_buffer {
    let stride = width * 4;
    let length = width * height * 4;

    let fd = create_anonymous_file(length as _);
    if fd < 0 {
        panic!("Failed to create temporary file");
    }
    let data = libc::mmap(
        std::ptr::null_mut(),
        length as _,
        libc::PROT_READ | libc::PROT_WRITE,
        libc::MAP_SHARED,
        fd,
        0,
    );

    if data == -1 as _ {
        libc::close(fd);
        panic!("Failed to mmap temporary file");
    }

    let pool = wl_request_constructor!(
        libwayland,
        shm,
        WL_SHM_CREATE_POOL,
        libwayland.wl_shm_pool_interface,
        fd,
        length
    );
    libc::close(fd);

    let target = data as *mut u8;
    for i in 0..width * height * 4 {
        *target.offset(i as _) = pixels[i as usize];
    }

    let buffer = wl_request_constructor!(
        libwayland,
        pool,
        WL_SHM_POOL_CREATE_BUFFER,
        libwayland.wl_buffer_interface,
        0,
        width,
        height,
        stride,
        wl_shm_format_WL_SHM_FORMAT_ARGB8888
    );

    libc::munmap(data, length as _);

    wl_shm_pool_destroy(libwayland, pool);
    buffer
}