Skip to content

Commit

Permalink
cxx-qt-lib: add QQmlApplicationEngine
Browse files Browse the repository at this point in the history
Related to KDAB#291
Related to KDAB#113
  • Loading branch information
ahayzen-kdab committed Jan 13, 2023
1 parent 03a40ac commit 4b065dc
Show file tree
Hide file tree
Showing 17 changed files with 237 additions and 40 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Added

- Support for container types: `QSet<T>`, `QHash<K, V>`, `QList<T>`, `QMap<K, V>`, `QVector<T>`
- Support for further types: `QByteArray`, `QCoreApplication`, `QGuiApplication`, `QModelIndex`, `QPersistentModelIndex`, `QQmlEngine`, `QStringList`, `QVector2D`, `QVector3D`, `QVector4D`
- Support for further types: `QByteArray`, `QCoreApplication`, `QGuiApplication`, `QModelIndex`, `QPersistentModelIndex`, `QQmlApplicationEngine`, `QQmlEngine`, `QStringList`, `QVector2D`, `QVector3D`, `QVector4D`
- Support for nesting objects in properties, invokables, and signals with `*mut T`

### Changed
Expand Down
24 changes: 24 additions & 0 deletions crates/cxx-qt-lib-headers/include/qml/qqmlapplicationengine.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// clang-format off
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// clang-format on
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
#pragma once

#ifdef CXX_QT_QML_FEATURE

#include <memory>

#include <QtQml/QQmlApplicationEngine>

namespace rust {
namespace cxxqtlib1 {

::std::unique_ptr<QQmlApplicationEngine>
qqmlapplicationengineNew();

}
}

#endif
5 changes: 5 additions & 0 deletions crates/cxx-qt-lib-headers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ pub fn write_headers(directory: impl AsRef<Path>) {
#[cfg(feature = "qt_gui")]
(include_str!("../include/gui/qvector4d.h"), "qvector4d.h"),
#[cfg(feature = "qt_qml")]
(
include_str!("../include/qml/qqmlapplicationengine.h"),
"qqmlapplicationengine.h",
),
#[cfg(feature = "qt_qml")]
(include_str!("../include/qml/qqmlengine.h"), "qqmlengine.h"),
(include_str!("../include/common.h"), "common.h"),
(include_str!("../include/convert.h"), "convert.h"),
Expand Down
8 changes: 2 additions & 6 deletions crates/cxx-qt-lib/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,7 @@ fn main() {
}

if feature_qt_qml_enabled {
rust_bridges.extend([
"qml/qqmlengine",
]);
rust_bridges.extend(["qml/qqmlapplicationengine", "qml/qqmlengine"]);
}

for bridge in &rust_bridges {
Expand Down Expand Up @@ -203,9 +201,7 @@ fn main() {
}

if feature_qt_qml_enabled {
cpp_files.extend([
"qml/qqmlengine",
]);
cpp_files.extend(["qml/qqmlapplicationengine", "qml/qqmlengine"]);
}

for cpp_file in &cpp_files {
Expand Down
3 changes: 3 additions & 0 deletions crates/cxx-qt-lib/src/qml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
//
// SPDX-License-Identifier: MIT OR Apache-2.0

mod qqmlapplicationengine;
pub use qqmlapplicationengine::QQmlApplicationEngine;

mod qqmlengine;
pub use qqmlengine::QQmlEngine;
22 changes: 22 additions & 0 deletions crates/cxx-qt-lib/src/qml/qqmlapplicationengine.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// clang-format off
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// clang-format on
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

#ifdef CXX_QT_GUI_FEATURE
#include "cxx-qt-lib/qqmlapplicationengine.h"

namespace rust {
namespace cxxqtlib1 {

::std::unique_ptr<QQmlApplicationEngine>
qqmlapplicationengineNew()
{
return ::std::make_unique<QQmlApplicationEngine>();
}

}
}
#endif
73 changes: 73 additions & 0 deletions crates/cxx-qt-lib/src/qml/qqmlapplicationengine.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0

#[cxx::bridge]
mod ffi {
unsafe extern "C++" {
include!("cxx-qt-lib/qstring.h");
type QString = crate::QString;
include!("cxx-qt-lib/qstringlist.h");
type QStringList = crate::QStringList;
include!("cxx-qt-lib/qurl.h");
type QUrl = crate::QUrl;

include!("cxx-qt-lib/qqmlapplicationengine.h");
type QQmlApplicationEngine;

/// 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 QQmlApplicationEngine>, path: &QString);

/// Adds path as a directory where the engine searches for native plugins for imported modules (referenced in the qmldir file).
#[rust_name = "add_plugin_path"]
fn addPluginPath(self: Pin<&mut QQmlApplicationEngine>, path: &QString);

/// Return the base URL for this engine.
/// The base URL is only used to resolve components when a relative URL is passed to the QQmlComponent constructor.
#[rust_name = "base_url"]
fn baseUrl(self: &QQmlApplicationEngine) -> QUrl;

/// Returns the list of directories where the engine searches for installed modules in a URL-based directory structure.
#[rust_name = "import_path_list"]
fn importPathList(self: &QQmlApplicationEngine) -> QStringList;

/// Loads the root QML file located at url.
fn load(self: Pin<&mut QQmlApplicationEngine>, url: &QUrl);

/// Returns the list of directories where the engine searches for native plugins for imported modules (referenced in the qmldir file).
#[rust_name = "plugin_path_list"]
fn pluginPathList(self: &QQmlApplicationEngine) -> QStringList;

/// Set the base URL for this engine to url.
#[rust_name = "set_base_url"]
fn setBaseUrl(self: Pin<&mut QQmlApplicationEngine>, url: &QUrl);

/// Sets paths as the list of directories where the engine searches for installed modules in a URL-based directory structure.
#[rust_name = "set_import_path_list"]
fn setImportPathList(self: Pin<&mut QQmlApplicationEngine>, paths: &QStringList);

/// Sets the list of directories where the engine searches for native plugins for imported modules (referenced in the qmldir file) to paths.
#[rust_name = "set_plugin_path_list"]
fn setPluginPathList(self: Pin<&mut QQmlApplicationEngine>, paths: &QStringList);
}

#[namespace = "rust::cxxqtlib1"]
unsafe extern "C++" {
#[doc(hidden)]
#[rust_name = "qqmlapplicationengine_new"]
fn qqmlapplicationengineNew() -> UniquePtr<QQmlApplicationEngine>;
}

impl UniquePtr<QQmlApplicationEngine> {}
}

pub use ffi::QQmlApplicationEngine;

impl QQmlApplicationEngine {
/// Create a new QQmlApplicationEngine
pub fn new() -> cxx::UniquePtr<Self> {
ffi::qqmlapplicationengine_new()
}
}
10 changes: 5 additions & 5 deletions examples/cargo_without_cmake/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ fn main() {
.qt_module("Network")
// Generate C++ from the `#[cxx_qt::bridge]` module
.file("src/cxxqt_object.rs")
.file("src/resources.rs")
.file("src/qml.rs")
// Generate C++ code from the .qrc file with the rcc tool
// https://doc.qt.io/qt-6/resources.html
.qrc("qml/qml.qrc")
// Tell CxxQtBuilder's internal cc::Build struct to compile the manually
// written C++ file in addition to the generated C++.
.cc_builder(|cc| {
// we are getting undefined symbol: _ZdlPvm, version Qt_5
// cc.flag_if_supported("-fno-sized-deallocation");
cc.file("cpp/run.cpp");
println!("cargo:rerun-if-changed=cpp/run.cpp");
// Include the cpp directory so CXX can find it
cc.include("cpp");
cc.file("cpp/register_types.cpp");
println!("cargo:rerun-if-changed=cpp/register_types.cpp");
})
.setup_linker()
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,16 @@
// SPDX-License-Identifier: MIT OR Apache-2.0

// ANCHOR: book_cargo_cpp_includes
#include <QtQml/QQmlApplicationEngine>
#include <QtQml/QQmlEngine>

#include "cxx-qt-gen/my_object.cxxqt.h"

// ANCHOR_END: book_cargo_cpp_includes

// ANCHOR: book_cargo_run_cpp
// extern "C" is important for the linker to be able to link this
// function with Rust code.
extern "C" void
run_cpp()
void
register_types()
{
// ANCHOR_END: book_cargo_run_cpp

// ANCHOR: book_cargo_run_qml
// TODO: creating binding, needs to survive
QQmlApplicationEngine* engine = new QQmlApplicationEngine();

const QUrl url(QStringLiteral("qrc:/main.qml"));

qmlRegisterType<MyObject>("com.kdab.cxx_qt.demo", 1, 0, "MyObject");

// TODO: this explodes due to calling qApp->arguments()
engine->load(url);
}
// ANCHOR_END: book_cargo_run_qml
23 changes: 11 additions & 12 deletions examples/cargo_without_cmake/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,12 @@

// ANCHOR: book_cargo_imports
mod cxxqt_object;
mod resources;
mod qml;
// ANCHOR_END: book_cargo_imports

// ANCHOR: book_cargo_extern_c
extern "C" {
fn run_cpp();
}
// ANCHOR_END: book_cargo_extern_c

// ANCHOR: book_cargo_rust_main
use cxx_qt_lib::{QGuiApplication, QQmlApplicationEngine, QUrl};

fn main() {
// ANCHOR: book_cargo_init_qrc
// Normally in a C++ program, global variables for the Qt Resource System are
Expand All @@ -26,14 +22,17 @@ fn main() {
// https://doc.qt.io/qt-6/resources.html#explicit-loading-and-unloading-of-embedded-resources

// Include the C++ code generated by rcc from the .qrc file
resources::ffi::qInitResources();
qml::ffi::qInitResources();
// ANCHOR_END: book_cargo_init_qrc

let mut app = cxx_qt_lib::QGuiApplication::new();
let mut app = QGuiApplication::new();

let mut engine = QQmlApplicationEngine::new();

qml::ffi::register_types();

// Call the C++ initialization code to start the QML GUI.
unsafe {
run_cpp();
if let Some(engine) = engine.as_mut() {
engine.load(&QUrl::from("qrc:/main.qml"));
}

if let Some(app) = app.as_mut() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@ pub mod ffi {
include!("qml.qrc.cpp");
fn qInitResources() -> i32;
}

unsafe extern "C++" {
include!("register_types.cpp");
fn register_types();
}
}
1 change: 1 addition & 0 deletions tests/qt_types_standalone/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ add_executable(${APP_NAME}
cpp/qpersistentmodelindex.h
cpp/qpoint.h
cpp/qpointf.h
cpp/qqmlapplicationengine.h
cpp/qqmlengine.h
cpp/qrect.h
cpp/qrectf.h
Expand Down
2 changes: 2 additions & 0 deletions tests/qt_types_standalone/cpp/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "qpersistentmodelindex.h"
#include "qpoint.h"
#include "qpointf.h"
#include "qqmlapplicationengine.h"
#include "qqmlengine.h"
#include "qrect.h"
#include "qrectf.h"
Expand Down Expand Up @@ -63,6 +64,7 @@ main(int argc, char* argv[])
runTest(QScopedPointer<QObject>(new QPersistentModelIndexTest));
runTest(QScopedPointer<QObject>(new QPointTest));
runTest(QScopedPointer<QObject>(new QPointFTest));
runTest(QScopedPointer<QObject>(new QQmlApplicationEngineTest));
runTest(QScopedPointer<QObject>(new QQmlEngineTest));
runTest(QScopedPointer<QObject>(new QRectTest));
runTest(QScopedPointer<QObject>(new QRectFTest));
Expand Down
47 changes: 47 additions & 0 deletions tests/qt_types_standalone/cpp/qqmlapplicationengine.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// clang-format off
// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// clang-format on
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
#pragma once

#include <QtCore/QCoreApplication>
#include <QtQml/QQmlApplicationEngine>
#include <QtTest/QTest>

#include "cxx-qt-gen/qqmlapplicationengine_cxx.cxx.h"

class QQmlApplicationEngineTest : public QObject
{
Q_OBJECT

private Q_SLOTS:
void construct()
{
// QQmlEngine requires a QApplication
std::vector<char*> args;
std::string path = "/path";
args.push_back(path.data());
auto argc = static_cast<int>(args.size());
QCoreApplication app(argc, args.data());

const auto engine = construct_qqmlapplicationengine();
QVERIFY(engine != nullptr);
QCOMPARE(engine->baseUrl(), QUrl(QStringLiteral("qrc:/kdab.qml")));
}

void read()
{
// QQmlEngine requires a QApplication
std::vector<char*> args;
std::string path = "/path";
args.push_back(path.data());
auto argc = static_cast<int>(args.size());
QCoreApplication app(argc, args.data());

QQmlApplicationEngine engine;
engine.setBaseUrl(QUrl(QStringLiteral("qrc:/kdab.qml")));
QVERIFY(read_qqmlapplicationengine(engine));
}
};
1 change: 1 addition & 0 deletions tests/qt_types_standalone/rust/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ fn main() {
.file("src/qpersistentmodelindex.rs")
.file("src/qpoint.rs")
.file("src/qpointf.rs")
.file("src/qqmlapplicationengine.rs")
.file("src/qqmlengine.rs")
.file("src/qrect.rs")
.file("src/qrectf.rs")
Expand Down
1 change: 1 addition & 0 deletions tests/qt_types_standalone/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod qmodelindex;
mod qpersistentmodelindex;
mod qpoint;
mod qpointf;
mod qqmlapplicationengine;
mod qqmlengine;
mod qrect;
mod qrectf;
Expand Down
Loading

0 comments on commit 4b065dc

Please sign in to comment.