-
Notifications
You must be signed in to change notification settings - Fork 78
/
nested_qobjects.rs
137 lines (118 loc) · 4.42 KB
/
nested_qobjects.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
// SPDX-FileContributor: Andrew Hayzen <[email protected]>
//
// SPDX-License-Identifier: MIT OR Apache-2.0
//! This example shows how a pointer from one Rust defined QObject to another Rust defined QObject can be used
// Currently, there seems to be a clippy bug, that says the `called` signals don't have `# Safety`
// docs, which they do have. So we disable the warning for now.
#![allow(clippy::missing_safety_doc)]
/// A CXX-Qt bridge which shows how a pointer from one Rust defined QObject to another Rust defined QObject can be used
// ANCHOR: book_macro_code
#[cxx_qt::bridge]
pub mod qobject {
// ANCHOR: book_extern_block
extern "RustQt" {
#[qobject]
#[qml_element]
#[qproperty(i32, counter)]
type InnerObject = super::InnerObjectRust;
}
// ANCHOR_END: book_extern_block
extern "RustQt" {
/// A signal showing how to refer to another QObject as an argument
///
/// # Safety
///
/// Due to a raw pointer this is considered unsafe in CXX
#[qsignal]
unsafe fn called(self: Pin<&mut InnerObject>, inner: *mut InnerObject);
}
extern "RustQt" {
#[qobject]
#[qml_element]
#[qproperty(*mut InnerObject, inner)]
type OuterObject = super::OuterObjectRust;
/// A signal showing how to refer to another QObject as an argument
///
/// # Safety
///
/// Due to a raw pointer this is considered unsafe in CXX
#[qsignal]
unsafe fn called(self: Pin<&mut OuterObject>, inner: *mut InnerObject);
}
unsafe extern "RustQt" {
/// Print the count of the given inner QObject
///
/// # Safety
///
/// As we deref a pointer in a public method this needs to be marked as unsafe
#[qinvokable]
#[cxx_name = "printCount"]
unsafe fn print_count(self: Pin<&mut OuterObject>, inner: *mut InnerObject);
/// Reset the counter of the inner QObject stored in the Q_PROPERTY
#[qinvokable]
fn reset(self: Pin<&mut OuterObject>);
}
impl cxx_qt::Constructor<()> for OuterObject {}
}
use core::pin::Pin;
/// The inner QObject
#[derive(Default)]
pub struct InnerObjectRust {
counter: i32,
}
/// The outer QObject which has a Q_PROPERTY pointing to the inner QObject
pub struct OuterObjectRust {
inner: *mut qobject::InnerObject,
}
impl Default for OuterObjectRust {
fn default() -> Self {
Self {
inner: std::ptr::null_mut(),
}
}
}
impl qobject::OuterObject {
/// Print the count of the given inner QObject
///
/// # Safety
///
/// As we deref a pointer in a public method this needs to be marked as unsafe
pub unsafe fn print_count(self: Pin<&mut Self>, inner: *mut qobject::InnerObject) {
if let Some(inner) = inner.as_ref() {
println!("Inner object's counter property: {}", inner.counter());
}
self.called(inner);
}
/// Reset the counter of the inner QObject stored in the Q_PROPERTY
pub fn reset(self: Pin<&mut Self>) {
// We need to convert the *mut T to a Pin<&mut T> so that we can reach the methods
if let Some(inner) = unsafe { self.inner().as_mut() } {
let pinned_inner = unsafe { Pin::new_unchecked(inner) };
// Now pinned inner can be used as normal
pinned_inner.set_counter(10);
}
// Retrieve *mut T
let inner = *self.inner();
unsafe { self.called(inner) };
}
}
impl cxx_qt::Initialize for qobject::OuterObject {
/// Initialize the QObject, creating a connection from one signal to another
fn initialize(self: core::pin::Pin<&mut Self>) {
// Example of connecting a signal from one QObject to another QObject
// this causes OuterObject::Called to trigger InnerObject::Called
self.on_called(|qobject, obj| {
// We need to convert the *mut T to a Pin<&mut T> so that we can reach the methods
if let Some(inner) = unsafe { qobject.inner().as_mut() } {
let pinned_inner = unsafe { Pin::new_unchecked(inner) };
// Now pinned inner can be used as normal
unsafe {
pinned_inner.called(obj);
}
}
})
.release();
}
}
// ANCHOR_END: book_macro_code