White-Oak / qml-rust

QML (Qt Quick) bindings for Rust language
MIT License
205 stars 18 forks source link

using rust and c++ in a Qt Creator project #44

Open seshonaar opened 7 years ago

seshonaar commented 7 years ago

Hi!

I'm currently trying to start from a standard Qt Creator project and delegate the "backend" to rust directly via ffi. But I still want to use c++ where the rust library doesn't have support yet (for example I need an QQuickImageProvider). I must say that I'm very close in achieving what I want, but I'm blocked by not having access to the native pointer of the QmlEngine. Do you think it would be possible to expose it to the external world, so it can be directly passed to c++? Just as some code reference I have now: I'm creating the engine in rust, pass it back to c++ in order to do some extra stuff with it (ex: attaching the image provider) and then pass it back to rust and call exec()

pub struct DicomContext {
    engine: QmlEngine,
    controller: Box<QMainWindowController>
}

impl DicomContext {
    pub fn new() -> Self {
        let mut engine = QmlEngine::new();
        let main_controller = MainWindowController {};
        let q_controller = QMainWindowController::new(main_controller);
        engine.set_and_store_property("controller", q_controller.get_qobj());
        // Load main window QML
        engine.load_url("qrc:/main.qml");

        DicomContext { engine: engine, controller: q_controller }
    }
}

#[no_mangle]
pub extern "C" fn create_context() -> *mut DicomContext {
    // Create an instance of DicomContext. 
    let context = DicomContext::new(); 

    // Put named_data into a Box, which moves it onto the heap. 
    let boxed_data = Box::new(context); 

    // Convert our Box<DicomContext> into a *mut DicomContext. Rust is no longer 
    // managing the destruction of boxed_data; we must (at some point in the 
    // future) convert this pointer back into a Box<DicomContext> so it can be 
    // deallocated. 
    Box::into_raw(boxed_data)
}

#[no_mangle] 
pub extern fn get_engine(ptr: *mut DicomContext) -> *mut qml::types::WQmlApplicationEngine { 
    let core = unsafe { 
        assert!(!ptr.is_null()); 
        &mut *ptr 
    }; 

    core.engine.get_ptr() // I don't have this :|
}

#[no_mangle]
pub extern "C" fn run(ptr: *mut DicomContext)  {
    println!("running...");

    if ptr.is_null() { 
        return 
    }

    {
        let context = unsafe { 
            assert!(!ptr.is_null()); 
            &mut *ptr 
        }; 

        context.engine.exec();
        context.engine.quit();
    }

    // let rust handle freeing the memory
    unsafe { Box::from_raw(ptr); }
}
seshonaar commented 7 years ago

and the c++ part '''

include

include

include

include "dicomimageprovider.h"

struct DicomContext;

extern "C" { void test_ffi(); DicomContext create_context(); //QmlEngine get_engine(DicomContext); void run(DicomContext); }

int main(int argc, char argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); DicomContext context = create_context(); // here I need the engine back from rust...but I don't have it //QQmlApplicationEngine* engine = get_engine(context); //engine->addImageProvider(QLatin1String("dicom"), new DicomImageProvider); run(context); return 0; }

'''