Skip to content

cxx-qt-lib: Add binding for QQmlApplicationEngine::singletonInstance #1140

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -17,6 +17,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased](https://github.com/KDAB/cxx-qt/compare/v0.7.0...HEAD)

### Added

- Add binding for `singletonInstance` of `QQmlApplicationEngine`, allowing access to singleton instances registered in the QML engine.

### Fixed

- Build warnings due to unused unsafe blocks since CXX 1.0.130
7 changes: 7 additions & 0 deletions crates/cxx-qt-lib/include/qml/qqmlapplicationengine.h
Original file line number Diff line number Diff line change
@@ -22,6 +22,13 @@ qqmlapplicationengineNew();
QQmlEngine&
qqmlapplicationengineAsQQmlEngine(QQmlApplicationEngine&);

#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
void*
qqmlapplicationengineSingletonInstance(QQmlApplicationEngine& engine,
QAnyStringView uri,
QAnyStringView typeName);
#endif

}
}

11 changes: 11 additions & 0 deletions crates/cxx-qt-lib/src/qml/qqmlapplicationengine.cpp
Original file line number Diff line number Diff line change
@@ -22,5 +22,16 @@ qqmlapplicationengineAsQQmlEngine(QQmlApplicationEngine& engine)
return static_cast<QQmlEngine&>(engine);
}

#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
void*
qqmlapplicationengineSingletonInstance(QQmlApplicationEngine& engine,
QAnyStringView uri,
QAnyStringView typeName)
{
return reinterpret_cast<void*>(
engine.singletonInstance<QObject*>(uri, typeName));
}
#endif

}
}
39 changes: 39 additions & 0 deletions crates/cxx-qt-lib/src/qml/qqmlapplicationengine.rs
Original file line number Diff line number Diff line change
@@ -68,6 +68,9 @@ mod ffi {

#[namespace = "rust::cxxqtlib1"]
unsafe extern "C++" {
include!("cxx-qt-lib/common.h");
type c_void = crate::c_void;

#[doc(hidden)]
#[rust_name = "qqmlapplicationengine_new"]
fn qqmlapplicationengineNew() -> UniquePtr<QQmlApplicationEngine>;
@@ -79,13 +82,33 @@ mod ffi {
) -> Pin<&mut QQmlEngine>;
}

#[cfg(any(cxxqt_qt_version_at_least_7, cxxqt_qt_version_at_least_6_5))]
unsafe extern "C++" {
Copy link
Contributor Author

@redstrate redstrate Dec 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This #[cfg] doesn't work I guess, so Qt5 and <6.5 builds will fail. A possible solution could be to separate this into a different cxx::bridge as suggested in this issue but that seems extreme?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fully support for cfg flags everywhere comes in #1133 and #1132 which i plan to look at next.

For now you could try instead of putting the cfg flag on the extern block itself put it on the method as this is passed through to CXX.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That does work, but the QAnyStringView inclusion is hitting the same problems as seen in #1141 :(

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment in #1141 i think this should work now, we fixed cfg not working on type aliases in CXX

include!("cxx-qt-lib/qanystringview.h");
type QAnyStringView<'a> = crate::QAnyStringView<'a>;
}

#[namespace = "rust::cxxqtlib1"]
unsafe extern "C++" {
#[doc(hidden)]
#[rust_name = "qqmlapplicationengine_singleton_instance"]
#[cfg(any(cxxqt_qt_version_at_least_7, cxxqt_qt_version_at_least_6_5))]
fn qqmlapplicationengineSingletonInstance(
ptr: Pin<&mut QQmlApplicationEngine>,
uri: QAnyStringView,
typeName: QAnyStringView,
) -> *mut c_void;
}

// QQmlApplicationEngine is not a trivial to CXX and is not relocatable in Qt
// as the following fails in C++. So we cannot mark it as a trivial type
// and need to use references or pointers.
// static_assert(QTypeInfo<QQmlApplicationEngine>::isRelocatable);
impl UniquePtr<QQmlApplicationEngine> {}
}

#[cfg(any(cxxqt_qt_version_at_least_7, cxxqt_qt_version_at_least_6_5))]
use crate::QAnyStringView;
use crate::QQmlEngine;
use core::pin::Pin;

@@ -101,4 +124,20 @@ impl QQmlApplicationEngine {
pub fn new() -> cxx::UniquePtr<Self> {
ffi::qqmlapplicationengine_new()
}

/// Returns the instance of a singleton type named typeName from the module specified by uri.
/// This is inherently unsafe as it does not perform any type checks.
/// This function was introduced in Qt 6.5.
#[cfg(any(cxxqt_qt_version_at_least_7, cxxqt_qt_version_at_least_6_5))]
pub unsafe fn singleton_instance<'a, T>(
self: Pin<&'a mut Self>,
uri: QAnyStringView,
type_name: QAnyStringView,
) -> Option<Pin<&'a mut T>> {
let ptr = ffi::qqmlapplicationengine_singleton_instance(self, uri, type_name);
if ptr.is_null() {
return None;
}
Some(Pin::new_unchecked(&mut *(ptr as *mut T)))
}
}