From 90aee97de678579f8aa3f43b387fcf499554b122 Mon Sep 17 00:00:00 2001 From: Andrew Hayzen Date: Thu, 8 Feb 2024 13:39:38 +0900 Subject: [PATCH] cxx-qt-lib: use cxx_qt::bridge and #[qsignal] in QQmlEngine This allows for us to declare a signal and listen to it. --- .../include/qml/qqmlapplicationengine.h | 4 ++++ .../src/qml/qqmlapplicationengine.cpp | 6 ++++++ .../src/qml/qqmlapplicationengine.rs | 19 +++++++++++++++++++ crates/cxx-qt-lib/src/qml/qqmlengine.rs | 18 ++++++++++++++---- examples/cargo_without_cmake/src/main.rs | 7 +++++++ examples/qml_minimal/qml/main.qml | 6 ++++++ 6 files changed, 56 insertions(+), 4 deletions(-) diff --git a/crates/cxx-qt-lib-headers/include/qml/qqmlapplicationengine.h b/crates/cxx-qt-lib-headers/include/qml/qqmlapplicationengine.h index ea7cafa1a..cf561a4d4 100644 --- a/crates/cxx-qt-lib-headers/include/qml/qqmlapplicationengine.h +++ b/crates/cxx-qt-lib-headers/include/qml/qqmlapplicationengine.h @@ -11,6 +11,7 @@ #include #include +#include namespace rust { namespace cxxqtlib1 { @@ -18,6 +19,9 @@ namespace cxxqtlib1 { ::std::unique_ptr qqmlapplicationengineNew(); +QQmlEngine& +qqmlapplicationengineAsQQmlEngine(QQmlApplicationEngine&); + } } diff --git a/crates/cxx-qt-lib/src/qml/qqmlapplicationengine.cpp b/crates/cxx-qt-lib/src/qml/qqmlapplicationengine.cpp index 8ed3e9aee..1e858de98 100644 --- a/crates/cxx-qt-lib/src/qml/qqmlapplicationengine.cpp +++ b/crates/cxx-qt-lib/src/qml/qqmlapplicationengine.cpp @@ -16,5 +16,11 @@ qqmlapplicationengineNew() return ::std::make_unique(); } +QQmlEngine& +qqmlapplicationengineAsQQmlEngine(QQmlApplicationEngine& engine) +{ + return static_cast(engine); +} + } } diff --git a/crates/cxx-qt-lib/src/qml/qqmlapplicationengine.rs b/crates/cxx-qt-lib/src/qml/qqmlapplicationengine.rs index 6440f6fc6..9e7b848a2 100644 --- a/crates/cxx-qt-lib/src/qml/qqmlapplicationengine.rs +++ b/crates/cxx-qt-lib/src/qml/qqmlapplicationengine.rs @@ -61,11 +61,22 @@ mod ffi { fn setOfflineStoragePath(self: Pin<&mut QQmlApplicationEngine>, dir: &QString); } + unsafe extern "C++" { + include!("cxx-qt-lib/qqmlengine.h"); + type QQmlEngine = crate::QQmlEngine; + } + #[namespace = "rust::cxxqtlib1"] unsafe extern "C++" { #[doc(hidden)] #[rust_name = "qqmlapplicationengine_new"] fn qqmlapplicationengineNew() -> UniquePtr; + + #[doc(hidden)] + #[rust_name = "qqmlapplicationengine_as_qqmlengine"] + fn qqmlapplicationengineAsQQmlEngine( + ptr: Pin<&mut QQmlApplicationEngine>, + ) -> Pin<&mut QQmlEngine>; } // QQmlApplicationEngine is not a trivial to CXX and is not relocatable in Qt @@ -75,9 +86,17 @@ mod ffi { impl UniquePtr {} } +use crate::QQmlEngine; +use core::pin::Pin; + pub use ffi::QQmlApplicationEngine; impl QQmlApplicationEngine { + /// Convert the existing [QQmlApplicationEngine] to a [QQmlEngine] + pub fn as_qqmlengine<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut QQmlEngine> { + ffi::qqmlapplicationengine_as_qqmlengine(self) + } + /// Create a new QQmlApplicationEngine pub fn new() -> cxx::UniquePtr { ffi::qqmlapplicationengine_new() diff --git a/crates/cxx-qt-lib/src/qml/qqmlengine.rs b/crates/cxx-qt-lib/src/qml/qqmlengine.rs index 3e160a093..790ba7ee1 100644 --- a/crates/cxx-qt-lib/src/qml/qqmlengine.rs +++ b/crates/cxx-qt-lib/src/qml/qqmlengine.rs @@ -3,8 +3,21 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 -#[cxx::bridge] +#[cxx_qt::bridge(cxx_file_stem = "qqmlengine")] mod ffi { + unsafe extern "C++Qt" { + include!("cxx-qt-lib/qqmlengine.h"); + type QQmlEngine; + + /// This signal is emitted when the QML loaded by the engine would like to exit from the event loop with the specified return code ret_code. + #[qsignal] + fn exit(self: Pin<&mut QQmlEngine>, ret_code: i32); + + /// This signal is emitted when the QML loaded by the engine would like to quit. + #[qsignal] + fn quit(self: Pin<&mut QQmlEngine>); + } + unsafe extern "C++" { include!("cxx-qt-lib/qstring.h"); type QString = crate::QString; @@ -13,9 +26,6 @@ mod ffi { include!("cxx-qt-lib/qurl.h"); type QUrl = crate::QUrl; - include!("cxx-qt-lib/qqmlengine.h"); - type QQmlEngine; - /// Adds path as a directory where the engine searches for installed modules in a URL-based directory structure. #[rust_name = "add_import_path"] fn addImportPath(self: Pin<&mut QQmlEngine>, path: &QString); diff --git a/examples/cargo_without_cmake/src/main.rs b/examples/cargo_without_cmake/src/main.rs index 0c7ebd1ba..2bc919727 100644 --- a/examples/cargo_without_cmake/src/main.rs +++ b/examples/cargo_without_cmake/src/main.rs @@ -28,6 +28,13 @@ fn main() { engine.load(&QUrl::from("qrc:/qt/qml/com/kdab/cxx_qt/demo/qml/main.qml")); } + if let Some(engine) = engine.as_mut() { + // Listen to a signal from the QML Engine + engine.as_qqmlengine().on_quit(|_| { + println!("QML Quit!"); + }); + } + // Start the app if let Some(app) = app.as_mut() { app.exec(); diff --git a/examples/qml_minimal/qml/main.qml b/examples/qml_minimal/qml/main.qml index beaf7fdee..8c693b692 100644 --- a/examples/qml_minimal/qml/main.qml +++ b/examples/qml_minimal/qml/main.qml @@ -51,6 +51,12 @@ Window { onClicked: myObject.sayHi(myObject.string, myObject.number) } + + Button { + text: qsTr("Quit") + + onClicked: Qt.quit() + } } } // ANCHOR_END: book_main_qml