Skip to content
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

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
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
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions crates/cxx-qt-lib/include/qml/qqmlapplicationengine.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

}
}

Expand Down
11 changes: 11 additions & 0 deletions crates/cxx-qt-lib/src/qml/qqmlapplicationengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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>;
Expand All @@ -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 :(

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;

Expand All @@ -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)))
}
}
Loading