qml-rust icon indicating copy to clipboard operation
qml-rust copied to clipboard

using rust and c++ in a Qt Creator project

Open seshonaar opened this issue 8 years ago • 1 comments
trafficstars

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 avatar Apr 22 '17 20:04 seshonaar

and the c++ part ''' #include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #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; }

'''

seshonaar avatar Apr 22 '17 20:04 seshonaar