nativeshell 0.1.0

NativeShell Rust package
Documentation
#![allow(clippy::from_over_into)]

use std::{mem::ManuallyDrop, os::raw::c_char};

use super::flutter_sys;
use glib::{glib_wrapper, Object};
use glib::{translate::*, Bytes};
use gtk::{Container, Widget};

use glib::object::Cast;
use glib::object::IsA;
use glib::GString;

glib_wrapper! {
    pub struct DartProject(Object<flutter_sys::FlDartProject,
        flutter_sys::FlDartProjectClass, DartProjectClass>);

    match fn {
        get_type => || gobject_sys::g_object_get_type(),
    }
}

impl DartProject {
    pub fn new() -> DartProject {
        unsafe { Object::from_glib_none(flutter_sys::fl_dart_project_new()).unsafe_cast() }
    }
}

glib_wrapper! {
    pub struct View(Object<flutter_sys::FlView,
        flutter_sys::FlViewClass, ViewClass>) @extends Container, Widget;

    match fn {
        get_type => || gtk_sys::gtk_container_get_type(),
    }
}

impl View {
    pub fn new<P: IsA<DartProject>>(project: &P) -> View {
        unsafe {
            Widget::from_glib_none(flutter_sys::fl_view_new(project.as_ref().to_glib_none().0))
                .unsafe_cast()
        }
    }
}

pub trait ViewExt: 'static {
    fn get_engine(&self) -> Engine;
}

impl<O: IsA<View>> ViewExt for O {
    fn get_engine(&self) -> Engine {
        unsafe {
            Object::from_glib_none(flutter_sys::fl_view_get_engine(
                self.as_ref().to_glib_none().0,
            ))
            .unsafe_cast()
        }
    }
}

glib_wrapper! {
    pub struct Engine(Object<flutter_sys::FlEngine,
        flutter_sys::FlEngineClass, EngineClass>);

    match fn {
        get_type => || gobject_sys::g_object_get_type(),
    }
}

pub trait EngineExt: 'static {
    fn get_binary_messenger(&self) -> BinaryMessenger;
}

impl<O: IsA<Engine>> EngineExt for O {
    fn get_binary_messenger(&self) -> BinaryMessenger {
        unsafe {
            Object::from_glib_none(flutter_sys::fl_engine_get_binary_messenger(
                self.as_ref().to_glib_none().0,
            ))
            .unsafe_cast()
        }
    }
}

glib_wrapper! {
    pub struct BinaryMessenger(Object<flutter_sys::FlBinaryMessenger,
        flutter_sys::FlBinaryMessengerClass, BinaryMessengerClass>);

    match fn {
        get_type => || gobject_sys::g_object_get_type(),
    }
}

glib_wrapper! {
    pub struct BinaryMessengerResponseHandle(Object<flutter_sys::FlBinaryMessengerResponseHandle,
        flutter_sys::FlBinaryMessengerResponseHandleClass, BinaryMessengerResponseHandleClass>);

    match fn {
        get_type => || gobject_sys::g_object_get_type(),
    }
}

pub trait BinaryMessengerExt: 'static {
    fn set_message_handler_on_channel<
        F: Fn(Bytes, &str, BinaryMessenger, BinaryMessengerResponseHandle) + 'static,
    >(
        &self,
        channel: &str,
        callback: F,
    );

    fn remove_message_handler_on_channel(&self, channel: &str);

    fn send_response<ResponseHandle: IsA<BinaryMessengerResponseHandle>>(
        &self,
        response_handle: ResponseHandle,
        response: Bytes,
    );

    fn send_message<F: FnOnce(Bytes) + 'static>(&self, channel: &str, message: Bytes, callback: F);

    fn post_message(&self, channel: &str, message: Bytes);
}

unsafe extern "C" fn message_handler(
    messenger: *mut flutter_sys::FlBinaryMessenger,
    channel: *const c_char,
    bytes: *mut glib_sys::GBytes,
    response_handle: *mut flutter_sys::FlBinaryMessengerResponseHandle,
    user_data: glib_sys::gpointer,
) {
    let b: Box<Box<dyn Fn(Bytes, &str, BinaryMessenger, BinaryMessengerResponseHandle)>> =
        Box::from_raw(user_data as *mut _);
    let b = ManuallyDrop::new(b);
    let messenger: BinaryMessenger =
        Object::from_glib_none(messenger as *mut gobject_sys::GObject).unsafe_cast();
    let response_handle: BinaryMessengerResponseHandle =
        Object::from_glib_none(response_handle as *mut gobject_sys::GObject).unsafe_cast();
    let channel: Option<GString> = from_glib_none(channel);
    let bytes: Bytes = from_glib_none(bytes);
    b(bytes, &channel.unwrap(), messenger, response_handle);
}

extern "C" fn dispose_callback(callback: glib_sys::gpointer) {
    let _: Box<Box<dyn Fn(Bytes, BinaryMessenger, BinaryMessengerResponseHandle)>> =
        unsafe { Box::from_raw(callback as *mut _) };
}

unsafe extern "C" fn message_callback(
    source_object: *mut gobject_sys::GObject,
    result: *mut gio_sys::GAsyncResult,
    user_data: glib_sys::gpointer,
) {
    let messenger: BinaryMessenger = Object::from_glib_none(source_object).unsafe_cast();
    let data: Bytes = from_glib_full(flutter_sys::fl_binary_messenger_send_on_channel_finish(
        messenger.to_glib_none().0,
        result,
        std::ptr::null_mut(),
    ));
    let b: Box<Box<dyn FnOnce(Bytes)>> = Box::from_raw(user_data as *mut _);
    b(data);
}

impl<O: IsA<BinaryMessenger>> BinaryMessengerExt for O {
    fn set_message_handler_on_channel<
        F: Fn(Bytes, &str, BinaryMessenger, BinaryMessengerResponseHandle) + 'static,
    >(
        &self,
        channel: &str,
        callback: F,
    ) {
        let b: Box<dyn Fn(Bytes, &str, BinaryMessenger, BinaryMessengerResponseHandle)> =
            Box::new(callback);
        let b = Box::new(b);
        unsafe {
            flutter_sys::fl_binary_messenger_set_message_handler_on_channel(
                self.as_ref().to_glib_none().0,
                channel.to_glib_none().0,
                Some(message_handler),
                Box::into_raw(b) as glib_sys::gpointer,
                Some(dispose_callback),
            );
        }
    }

    fn remove_message_handler_on_channel(&self, channel: &str) {
        unsafe {
            flutter_sys::fl_binary_messenger_set_message_handler_on_channel(
                self.as_ref().to_glib_none().0,
                channel.to_glib_none().0,
                None,
                std::ptr::null_mut(),
                None,
            );
        }
    }

    fn send_response<ResponseHandle: IsA<BinaryMessengerResponseHandle>>(
        &self,
        response_handle: ResponseHandle,
        response: Bytes,
    ) {
        unsafe {
            flutter_sys::fl_binary_messenger_send_response(
                self.as_ref().to_glib_none().0,
                response_handle.as_ref().to_glib_none().0,
                response.to_glib_none().0,
                std::ptr::null_mut(),
            );
        }
    }

    fn send_message<F: FnOnce(Bytes) + 'static>(&self, channel: &str, message: Bytes, callback: F) {
        let b: Box<dyn FnOnce(Bytes)> = Box::new(callback);
        let b = Box::new(b);
        unsafe {
            flutter_sys::fl_binary_messenger_send_on_channel(
                self.as_ref().to_glib_none().0,
                channel.to_glib_none().0,
                message.to_glib_none().0,
                std::ptr::null_mut(),
                Some(message_callback),
                Box::into_raw(b) as glib_sys::gpointer,
            );
        }
    }

    fn post_message(&self, channel: &str, message: Bytes) {
        unsafe {
            flutter_sys::fl_binary_messenger_send_on_channel(
                self.as_ref().to_glib_none().0,
                channel.to_glib_none().0,
                message.to_glib_none().0,
                std::ptr::null_mut(),
                None,
                std::ptr::null_mut(),
            );
        }
    }
}