Skip to content

Commit 94d0b30

Browse files
LeonMatthesKDABBe-ingahayzen-kdab
authored
Book: Update QObjects chapter to v0.4 (#320)
Co-authored-by: Be <[email protected]> Co-authored-by: Andrew Hayzen <[email protected]>
1 parent eb9a46e commit 94d0b30

17 files changed

+367
-124
lines changed

book/src/SUMMARY.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@ SPDX-License-Identifier: MIT OR Apache-2.0
1111

1212
---
1313

14-
- [Getting-Started](./getting-started/index.md)
14+
- [Getting Started](./getting-started/index.md)
1515
- [QObjects in Rust](./getting-started/1-qobjects-in-rust.md)
1616
- [Our first CXX-Qt module](./getting-started/2-our-first-cxx-qt-module.md)
1717
- [Exposing to QML](./getting-started/3-exposing-to-qml.md)
1818
- [Creating the QML GUI](./getting-started/4-qml-gui.md)
1919
- [Building with CMake](./getting-started/5-cmake-integration.md)
2020
- [Building with Cargo](./getting-started/6-cargo-executable.md)
2121
- [QObject](./qobject/index.md)
22-
- [Macro](./qobject/macro.md)
23-
- [QObject marked Struct](./qobject/qobject_struct.md)
24-
- [Cpp Object](./qobject/cpp_object.md)
25-
- [Signals enum](./qobject/signals_enum.md)
22+
- [`#[cxx_qt::bridge]` - Bridge Macro](./qobject/bridge-macro.md)
23+
- [`#[cxx_qt::qobject]` - Defining QObjects](./qobject/qobject_struct.md)
24+
- [`#[cxx_qt::qsignals]` - Signals enum](./qobject/signals_enum.md)
25+
- [`qobject::T` - The generated QObject](./qobject/generated-qobject.md)
2626
- [CxxQtThread](./qobject/cxxqtthread.md)
2727
- [Concepts](./concepts/index.md)
2828
- [Bridge](./concepts/bridge.md)

book/src/concepts/nested_objects.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ A nested object is referred to by it's path relative to `crate`, the second last
1919
2020
To use this as a property in another object write `secondary_object: crate::mymod::cxx_qt_secondary_object::CppObj` as the property.
2121
22-
For use as a parameter in an invokable write `secondary_object: &mut crate::mymod::cxx_qt_secondary_object::CppObj` as the parameter. Then the `secondary_object` parameter can be used via the normal [`CppObj`](../qobject/cpp_object.md) methods.
22+
For use as a parameter in an invokable write `secondary_object: &mut crate::mymod::cxx_qt_secondary_object::CppObj` as the parameter. Then the `secondary_object` parameter can be used via the normal [`CppObj`](../qobject/generated-qobject.md) methods.
2323
2424
The following example shows a nested object as a property and parameter.
2525

book/src/getting-started/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Take a look at the CXX documentation here: [https://cxx.rs/](https://cxx.rs/)
2626

2727
### What this guide covers
2828

29-
During this getting-started guide we'll first take a look at how CXX-Qt integrates with Qt's object system to allow the [definition of QObjects in Rust](./1-qobjects-in-rust.md).
29+
During this getting started guide we'll first take a look at how CXX-Qt integrates with Qt's object system to allow the [definition of QObjects in Rust](./1-qobjects-in-rust.md).
3030
Then we'll dive straight into practice and define our first [QObject in Rust](./2-our-first-cxx-qt-module.md).
3131
Once we've done that, its time to [expose the defined QObject to QML](./3-exposing-to-qml.md).
3232
Followed by actually [defining our GUI using QML](./4-qml-gui.md).

book/src/qobject/bridge-macro.md

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<!--
2+
SPDX-FileCopyrightText: 2021 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
3+
SPDX-FileContributor: Andrew Hayzen <[email protected]>
4+
5+
SPDX-License-Identifier: MIT OR Apache-2.0
6+
-->
7+
8+
# `#[cxx_qt::bridge]` Macro
9+
10+
The `#[cxx_qt::bridge]` macro functions very similarly to the [`#[cxx::bridge]`](https://docs.rs/cxx/latest/cxx/attr.bridge.html). This macro needs to be written above a Rust module definition.
11+
This Rust module will then function like a normal CXX bridge, whilst also supporting the additional features added by CXX-Qt. Refer to the [the CXX documentation](https://cxx.rs/) for details on how to describe the language boundary.
12+
Also don't forget to add the Rust source file to the CxxQtBuilder in your build.rs script.
13+
For instructions, see the [Getting Started guide](../getting-started/5-cmake-integration.md).
14+
15+
## Filename
16+
A C++ header file will be generated for every Rust file with a `#[cxx_qt::bridge]` module listed with [`CxxQtBuilder::file`](https://docs.rs/cxx-qt-build/latest/cxx_qt_build/struct.CxxQtBuilder.html#method.file).
17+
18+
By default, the name of the generated C++ header file will be the name of the module, followed by `.cxxqt.h`.
19+
Our plan is to change this to use the Rust file name instead. Progress on this can be tracked in [#200](https://github.com/KDAB/cxx-qt/pull/200).
20+
21+
This filename can also be changed using the `cxx_file_stem` attribute.
22+
The following example results in a header file named: `types.cxxqt.h`.
23+
``` rust, ignore
24+
{{#include ../../../examples/qml_features/rust/src/types.rs:book_cxx_file_stem}}
25+
// ...
26+
}
27+
```
28+
29+
Currently, cxx-qt-gen writes all generated header files into a single folder.
30+
Therefore you need to be careful to not produce two header files with the same filename.
31+
In future we plan to use the entire module path to disambiguate this.
32+
Progress on this can be tracked in [#19](https://github.com/KDAB/cxx-qt/issues/19).
33+
34+
## C++ namespace
35+
Just like on a `#[cxx::bridge]`, the C++ namespace of the bridge can be changed using the `namespace` attribute.
36+
37+
```rust,ignore,noplayground
38+
{{#include ../../../examples/qml_features/rust/src/threading.rs:book_namespace_macro}}
39+
// ...
40+
}
41+
```
42+
This will generate a header file named `threading_website.cxxqt.h` with all C++ items included in the `cxx_qt::website` namespace.
43+
44+
When accessing a type from the bridge module in C++, access it through the C++ namespace:
45+
```rust,ignore,noplayground
46+
{{#include ../../../examples/qml_features/cpp/main.cpp:book_namespace_register}}
47+
```

book/src/qobject/cpp_object.md

-40
This file was deleted.

book/src/qobject/cxxqtthread.md

+17-3
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,30 @@ SPDX-License-Identifier: MIT OR Apache-2.0
77

88
# CxxQtThread
99

10-
`CxxQtThread<T>` is used for [threading](../concepts/threading.md) with QObject#s and allows you to queue events from a background thread to occur on the Qt event loop.
10+
`CxxQtThread<T>` is used for easy [threading](../concepts/threading.md) with QObjects.
11+
The QObjects generated by CXX-Qt are neither [`Send`](https://doc.rust-lang.org/std/marker/trait.Send.html) nor [`Sync`](https://doc.rust-lang.org/std/marker/trait.Sync.html).
12+
Therefore they may not be passed between threads nor accessed from multiple threads.
1113

12-
To access the `CxxQtThread<T>` use the `qt_thread(&self)` method on the [`CppObj`](./cpp_object.md) or on the C++ pointer of the QObject.
14+
`CxxQtThread<T>` is an object that allows you to queue closures safely onto the Qt thread that the `qobject::T` lives on.
15+
This object is `Send` and can therefore be moved into other threads.
16+
It allows you to queue events from a different thread to occur on the thread of the `qobject::T` by using the Qt Event Loop.
17+
18+
To access the `CxxQtThread<T>` use the `qt_thread(&self)` method on a [`qobject::T`](./generated-qobject.md).
1319

1420
```rust,ignore,noplayground
1521
{{#include ../../../examples/qml_features/rust/src/threading.rs:book_qt_thread}}
1622
```
1723

18-
The `CxxQtThread<T>` can then be moved into the Rust thread, a `queue(fn(ctx: Pin<&mut TQt>) -> bool` is used to queue a Rust function pointer onto the Qt event loop. The first argument in the function pointer is a pinned pointer to the C++ side of the QObject.
24+
The `CxxQtThread<T>` can then be moved into any Rust thread.
25+
The `queue` function can then be used to queue a [closure](https://doc.rust-lang.org/book/ch13-01-closures.html) onto the Qt event loop:
26+
``` rust,ignore,noplayground
27+
fn queue(&self, f: F) -> Result<(), cxx::Exception>
28+
where F: impl FnOnce(ctx: Pin<&mut TQt>) + Send + 'static
29+
```
30+
The first argument of the closure is a pinned mutable reference to the `qobject::T`.
31+
With this parameter, you can then update the QObject to reflect any state changes that have occured in the background thread.
1932

2033
```rust,ignore,noplayground
2134
{{#include ../../../examples/qml_features/rust/src/threading.rs:book_qt_thread_queue}}
2235
```
36+
[Full example](https://github.com/KDAB/cxx-qt/blob/main/examples/qml_features/rust/src/threading.rs)

book/src/qobject/generated-qobject.md

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<!--
2+
SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
3+
SPDX-FileContributor: Andrew Hayzen <[email protected]>
4+
5+
SPDX-License-Identifier: MIT OR Apache-2.0
6+
-->
7+
8+
# `qobject::T` - The generated QObject
9+
10+
One of the key features of CXX-Qt is the ability to create your own QObjects from Rust.
11+
This is what the [`#[cxx_qt::qobject]` macro](./qobject_struct.md) is for.
12+
This page serves to document the details of what is generated and how to interact with the generated QObject from Rust.
13+
14+
The `#[cxx_qt::qobject]` macro generates a QObject for a given Rust struct.
15+
Whilst this QObject is a C++ type, CXX-Qt will automatically wrap it as a [CXX Opaque Type](https://cxx.rs/extern-c++.html#opaque-c-types).
16+
These generated QObjects are accessible to Rust in a generated module with the name `qobject`. Each struct `T`'s generated QObject is accessible as `qobject::T`.
17+
18+
## Anatomy
19+
20+
Any QObject generated by CXX-Qt is just a C++ QObject subclass that owns an instance of the Rust struct.
21+
The instance of the Rust struct is constructed using its [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) implementation in the C++ constructor.
22+
Therefore implementing `Default` on the Rust struct is currently mandatory.
23+
24+
The C++ object will defer any property state to the Rust struct, and is therefore only a thin wrapper.
25+
The data for `Q_PROPERTY`s is stored in the Rust struct. The property getters and setters modify the Rust struct internally.
26+
27+
Additionally, CXX-Qt generates methods on this struct that help you interact with Qt functionality.
28+
This includes access to the [`CxxQtThread` struct](./cxxqtthread.md), as well as a function to emit signals.
29+
30+
## Referencing another QObject
31+
32+
The `qobject::T` type is defined both within the CXX-Qt bridge, as well as the surrounding module.
33+
The simplest way to reference it is from the surrounding module.
34+
35+
Example:
36+
``` rust,ignore,noplayground
37+
// In file qt_types.rs
38+
#[cxx_qt::bridge]
39+
mod ffi {
40+
#[cxx_qt::qobject]
41+
#[derive(Default)]
42+
pub struct MyObject {}
43+
}
44+
```
45+
46+
``` rust,ignore,noplayground
47+
// In another module
48+
fn my_function(parameter: &crate::qt_types::qobject::MyObject) { /* ... */ }
49+
```
50+
51+
Unfortunately, nested QObjects aren't yet supported by CXX-Qt.
52+
Progress can be tracked in [#299](https://github.com/KDAB/cxx-qt/issues/299).
53+
54+
## `impl qobject::T`
55+
As mentioned before, the C++ QObject is exposed to Rust as an opaque CXX type.
56+
This allows you to implement methods for it in Rust using normal `impl` blocks.
57+
Because `qobject::T` is an opaque C++ type, the same rules as with normal CXX opaque types apply.
58+
Most importantly this means that the type may never be accessed by value or by mutable self reference directly.
59+
Rather, all methods must use either `&self` or `self: Pin<&mut Self>` as the self types. This prevents Rust from moving the data in memory, which would invalidate C++ pointers to it.
60+
61+
For more information about pinning, refer to the [pin documentation](https://doc.rust-lang.org/std/pin/).
62+
63+
In addition to methods that extend the Rust interface of a `qobject::T`, you may also mark methods within an `impl qobject::T` block with the `#[qinvokable]` attribute.
64+
These methods will be exposed to the C++ QObject and can be called by C++ or QML.
65+
See the [QObject page](./qobject_struct.md#invokables) for more details.
66+
67+
## Available Functions
68+
69+
Every `qobject::T` struct provides the following methods:
70+
71+
### Access to the Qt thread
72+
``` rust,ignore,noplayground
73+
fn qt_thread(&self) -> UniquePtr<CxxQtThread>
74+
```
75+
This function provides you with a handle to the Qt thread that the QObject resides in.
76+
This is helpful as the QObject itself does not implement [Send](https://doc.rust-lang.org/std/marker/trait.Send.html) nor [Sync](https://doc.rust-lang.org/std/marker/trait.Sync.html).
77+
The CxxQtThread however is Send and can therefore be moved into a different thread.
78+
By using the CxxQtThread's `queue` method, you may then queue a Rust closure onto the Qt thread again.
79+
The closure also takes a pinned mutable reference to the QObject, so that it can modify it.
80+
81+
See the [CxxQtThread page](./cxxqtthread.md) for more details.
82+
83+
### Signal emission
84+
``` rust,ignore,noplayground
85+
fn emit(self: Pin<&mut Self>, signal: /*Your Signals enum goes here*/)
86+
```
87+
If there is a [Signals enum](./signals_enum.md) defined, CXX-Qt will generate the appropriate `emit` function to allow you to emit signals.
88+
89+
See the [Signals enum page](./signals_enum.md) for more details.
90+
91+
### Access to internal Rust struct
92+
For every field in the Rust struct, CXX-Qt will generate appropriate getters and setters.
93+
See the [QObject page](./qobject_struct.md#properties) for details.
94+
95+
There is also an advanced way to access the data in the internal Rust struct:
96+
``` rust,ignore,noplayground
97+
fn rust(&self) -> &T
98+
unsafe fn rust_mut(self: Pin<&mut Self>) -> &mut T
99+
```
100+
Where `T` is the struct with the `#[cxx_qt::qobject]` macro.
101+
102+
This allows you to directly manipulate the internal Rust struct without having to use the generated accessor methods.
103+
104+
You may notice that the mutable version of this is `unsafe` to call.
105+
This is by design.
106+
Modifying a field that corresponds to a `#[qproperty]` without calling the appropriate changed signal may cause a logic error in C++/QML code.
107+
Therefore all direct access to a struct that is wrapped in a QObject is unsafe!
108+
109+
You may modify the struct and then manually call the required changed signals.
110+
111+
For safe access, prefer using the generated accessor methods for both [properties](./qobject_struct.md#properties), as well as [normal fields](./qobject_struct.md#private-methods-and-fields).

book/src/qobject/index.md

+12-6
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,16 @@ SPDX-License-Identifier: MIT OR Apache-2.0
77

88
# QObject
99

10-
A QObject is constructed with the following parts
10+
A QObject defined by CXX-Qt supports many features and is made up of quite a few parts.
11+
12+
This chapter goes into details on these.
13+
For a simpler introduction, take a look at our [Getting Started guide](../getting-started/index.md).
14+
15+
QObject Features and Parts:
16+
* [`#[cxx_qt::bridge]` - The macro around the module](./bridge-macro.md)
17+
* [`#[cxx_qt::qobject]` - Marking a Rust struct as a QObject](./qobject_struct.md)
18+
* [`#[cxx_qt::qsignals(T)]` - An enum for defining signals](./signals_enum.md)
19+
* [`qobject:T` - The generated QObject](./generated-qobject.md)
20+
* [`CxxQtThread` - Queueing closures onto the Qt event loop](./cxxqtthread.md)
21+
1122

12-
* [A macro around the module](./macro.md)
13-
* [A QObject marked struct defining properties and invokables](./qobject_struct.md)
14-
* [Cpp Object wrapper](./cpp_object.md)
15-
* [A Signals enum for defining signals](./signals_enum.md)
16-
* [Queueing function pointers onto the Qt thread](./cxxqtthread.md)

book/src/qobject/macro.md

-38
This file was deleted.

0 commit comments

Comments
 (0)