Skip to content

Commit

Permalink
Merge branch 'woboq:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrianEddy authored Nov 6, 2023
2 parents 98ebed1 + 855840e commit 59029b9
Show file tree
Hide file tree
Showing 14 changed files with 282 additions and 35 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [Unreleased]

## 0.2.11 2023-11-03 (qttype only)

- reenable `cargo:rustc-cdylib-link-arg=-Wl,-rpath,` command even if it is depracated as it broke people's build

## 0.2.10 2023-11-03

- qttypes: detect MSVC and MinGW incompatibilities
- qttypes: Added wrapper around QSettings
- Added QmlEngine::invoke_method_noreturn
- Added QmlEngine::trim_component_cache and QmlEngine::clear_component_cache

## 0.2.9 2023-06-15

- Implement QMetaType for QStringList and QVariantMap
Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ members = [
'examples/qenum',
'examples/nested_qobjects',
]

resolver = "2"
52 changes: 29 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,32 +289,38 @@ method. Now send us a Pull Request. 🙂
[`QVariant`]: https://docs.rs/qmetaobject/latest/qmetaobject/struct.QVariant.html
[docs.qttypes]: https://docs.rs/qttypes/latest/qttypes/#cargo-features

## Comparison with other projects
## Comparison to Other Projects

This crate objective is to make idiomatic Rust bindings for QML (and only QML, no QWidgets or other
non-graphical Qt API) in a way that doesn't need you to know or use C++ and other build system.
This crates is the best achieving this.
The primary goal of this crate is to provide idiomatic Rust bindings for QML.
It focuses solely on QML, not QWidgets or any other non-graphical Qt API.
The aim is to eliminate the need for users to know or use C++ and other build systems.
This crate excels in achieving this goal.

* **[CXX-Qt](https://github.com/KDAB/cxx-qt/)** still makes you to write a bit of boiler-plate code
in C++ and use extra build step to compile the C++.
CXX-Qt is ideal to bring some Rust in an existing C++ project. But less so when you just want to
make an UI for a Rust-only application.
* **[CXX-Qt](https://github.com/KDAB/cxx-qt/)** is an ideal solution for incorporating some Rust into an existing C++ project.
CXX-Qt is newer than this crate and utilizes Rust features such as attribute macro,
which didn't exist when the qmetaobject crate was designed.
(Only derive procedural macro were available in stable Rust at that time)

The CXX-Qt is also more recent that this crate and make use of Rust features such as attribute
macro, that did not exist when the qmetaobject crate was designed.
(Only derive procedural macro were available in stable rust rust at the time)
* The **[Rust Qt Binding Generator](https://invent.kde.org/sdk/rust-qt-binding-generator)**
is another project that aids in integrating Rust logic into an existing C++/Qt project.
This project was also developed before Rust had procedural macros, so it uses an external .json file to generate C++ and Rust code.

* Similarly, the **[Rust Qt Binding Generator](https://invent.kde.org/sdk/rust-qt-binding-generator)**
is another project that helps to integrate Rust logic in an existing C++/Qt project. This was also
created before rust had procedural macros, so it uses an external .json file to generate C++ and
Rust code.

* There exist also a bunch of older crates that tries to provide Rust binding around the Qt C++ API.
* There are also several older crates that attempted to provide Rust binding around the Qt C++ API.
Often automatically generated, these bindings are not idiomatic Rust, require unsafe code to use,
and are not maintained anymore.
and are no longer maintained.

* **[Slint](https://slint.rs)** is a project created by the author of this crate.
Slint is not a QML or Qt binding, but a new language inspired from QML, entirely implemented in Rust.
It shares the same objective of providing a means to add a UI to a Rust project with idiomatic Rust API, but instead of using QML for the UI, it uses its own language.\
[![Slint Logo](https://slint.dev/logo/slint-logo-simple-light.svg)](https://slint.rs)

The qmetaobject crate is currently only being passively maintained as focus has shifted towards developing Slint.
You are encouraged to explore [Slint](https://slint.rs) as an exciting, innovative alternative for creating GUI in Rust projects.

## Applications built with this crate

* https://github.com/gyroflow/gyroflow
![Gyroflow screenshot](https://github.com/gyroflow/gyroflow/blob/master/resources/screenshot.jpg)

* **[Slint](https://slint-ui.com)** is a project created by the same author of this crate.
It is not a QML or Qt binding at all, but rather a new language similar to QML, entirely
implemented in Rust.
It has the same goal as providing a new to add a UI to a Rust project with idiomatic Rust API,
but instead of using QML for the UI, it uses its own language.
* https://github.com/kalaksi/lightkeeper
![LightKeeper screenshot](https://github.com/kalaksi/lightkeeper/blob/master/doc/images/LightkeeperRM-overview.png)
2 changes: 1 addition & 1 deletion examples/graph/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "graph"
version = "0.1.0"
edition = "2018"
authors = ["Olivier Goffart <ogoffart@woboq.com>"]
authors = ["Olivier Goffart <olivier.goffart@slint.dev>"]
build = "build.rs"

[dependencies]
Expand Down
2 changes: 1 addition & 1 deletion examples/qmlextensionplugins/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "qmlextensionplugins"
version = "0.1.0"
edition = "2018"
authors = ["Olivier Goffart <ogoffart@woboq.com>"]
authors = ["Olivier Goffart <olivier.goffart@slint.dev>"]

[lib]
name = "qmlqtimeexampleplugin"
Expand Down
2 changes: 1 addition & 1 deletion examples/todos/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "todos"
version = "0.1.0"
edition = "2018"
authors = ["Olivier Goffart <ogoffart@woboq.com>"]
authors = ["Olivier Goffart <olivier.goffart@slint.dev>"]

[dependencies]
qmetaobject = { path = "../../qmetaobject" }
Expand Down
6 changes: 3 additions & 3 deletions qmetaobject/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[package]
name = "qmetaobject"
version = "0.2.9"
version = "0.2.10"
edition = "2018"
authors = ["Olivier Goffart <ogoffart@woboq.com>"]
authors = ["Olivier Goffart <olivier.goffart@slint.dev>"]
build = "build.rs"
description = "Expose rust object to Qt and QML."
readme = "../README.md"
Expand All @@ -19,7 +19,7 @@ widgets = ["qttypes/qtwidgets"]

[dependencies]
qttypes = { path = "../qttypes", version = "0.2.0", features = ["qtquick"] }
qmetaobject_impl = { path = "../qmetaobject_impl", version = "=0.2.9"}
qmetaobject_impl = { path = "../qmetaobject_impl", version = "=0.2.10"}
lazy_static = "1.0"
cpp = "0.5.6"
log = { version = "0.4", optional = true }
Expand Down
47 changes: 47 additions & 0 deletions qmetaobject/src/qtdeclarative.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,53 @@ impl QmlEngine {
})
}

/// This method is the same as [invoke_method] but does not capture or return function's return value
pub fn invoke_method_noreturn(&mut self, name: QByteArray, args: &[QVariant]) {
let args_size = args.len();
let args_ptr = args.as_ptr();

assert!(args_size <= 9);

cpp!(unsafe [
self as "QmlEngineHolder *",
name as "QByteArray",
args_size as "size_t",
args_ptr as "QVariant *"
] {
auto robjs = self->engine->rootObjects();
if (robjs.isEmpty()) {
return;
}

#define INVOKE_METHOD(...) QMetaObject::invokeMethod(robjs.first(), name __VA_ARGS__);
switch (args_size) {
case 0: INVOKE_METHOD(); break;
case 1: INVOKE_METHOD(, Q_ARG(QVariant, args_ptr[0])); break;
case 2: INVOKE_METHOD(, Q_ARG(QVariant, args_ptr[0]), Q_ARG(QVariant, args_ptr[1])); break;
case 3: INVOKE_METHOD(, Q_ARG(QVariant, args_ptr[0]), Q_ARG(QVariant, args_ptr[1]), Q_ARG(QVariant, args_ptr[2])); break;
case 4: INVOKE_METHOD(, Q_ARG(QVariant, args_ptr[0]), Q_ARG(QVariant, args_ptr[1]), Q_ARG(QVariant, args_ptr[2]), Q_ARG(QVariant, args_ptr[3])); break;
case 5: INVOKE_METHOD(, Q_ARG(QVariant, args_ptr[0]), Q_ARG(QVariant, args_ptr[1]), Q_ARG(QVariant, args_ptr[2]), Q_ARG(QVariant, args_ptr[3]), Q_ARG(QVariant, args_ptr[4])); break;
case 6: INVOKE_METHOD(, Q_ARG(QVariant, args_ptr[0]), Q_ARG(QVariant, args_ptr[1]), Q_ARG(QVariant, args_ptr[2]), Q_ARG(QVariant, args_ptr[3]), Q_ARG(QVariant, args_ptr[4]), Q_ARG(QVariant, args_ptr[5])); break;
case 7: INVOKE_METHOD(, Q_ARG(QVariant, args_ptr[0]), Q_ARG(QVariant, args_ptr[1]), Q_ARG(QVariant, args_ptr[2]), Q_ARG(QVariant, args_ptr[3]), Q_ARG(QVariant, args_ptr[4]), Q_ARG(QVariant, args_ptr[5]), Q_ARG(QVariant, args_ptr[6])); break;
case 8: INVOKE_METHOD(, Q_ARG(QVariant, args_ptr[0]), Q_ARG(QVariant, args_ptr[1]), Q_ARG(QVariant, args_ptr[2]), Q_ARG(QVariant, args_ptr[3]), Q_ARG(QVariant, args_ptr[4]), Q_ARG(QVariant, args_ptr[5]), Q_ARG(QVariant, args_ptr[6]), Q_ARG(QVariant, args_ptr[7])); break;
case 9: INVOKE_METHOD(, Q_ARG(QVariant, args_ptr[0]), Q_ARG(QVariant, args_ptr[1]), Q_ARG(QVariant, args_ptr[2]), Q_ARG(QVariant, args_ptr[3]), Q_ARG(QVariant, args_ptr[4]), Q_ARG(QVariant, args_ptr[5]), Q_ARG(QVariant, args_ptr[6]), Q_ARG(QVariant, args_ptr[7]), Q_ARG(QVariant, args_ptr[8])); break;
}
#undef INVOKE_METHOD
})
}

pub fn trim_component_cache(&self) {
cpp!(unsafe [self as "QmlEngineHolder *"] {
self->engine->trimComponentCache();
})
}

pub fn clear_component_cache(&self) {
cpp!(unsafe [self as "QmlEngineHolder *"] {
self->engine->clearComponentCache();
})
}

/// Give a QObject to the engine by wrapping it in a QJSValue
///
/// This will create the C++ object.
Expand Down
4 changes: 2 additions & 2 deletions qmetaobject_impl/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[package]
name = "qmetaobject_impl"
version = "0.2.9"
version = "0.2.10"
edition = "2018"
authors = ["Olivier Goffart <ogoffart@woboq.com>"]
authors = ["Olivier Goffart <olivier.goffart@slint.dev>"]
description = "Custom derive for the qmetaobject crate."
readme = "../README.md"
license = "MIT"
Expand Down
5 changes: 3 additions & 2 deletions qttypes/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[package]
name = "qttypes"
version = "0.2.9"
version = "0.2.11"
edition = "2018"
authors = ["Olivier Goffart <ogoffart@woboq.com>"]
authors = ["Olivier Goffart <olivier.goffart@slint.dev>"]
build = "build.rs"
description = "Manually maintained buildings for Qt value types"
readme = "README.md"
Expand Down Expand Up @@ -47,6 +47,7 @@ semver = "1"

[dev-dependencies]
cpp_build = "0.5.6"
tempfile = { version = "3.4.0", default-features = false }

[package.metadata.docs.rs]
dependencies = [ "qtbase5-dev", "qtdeclarative5-dev" ]
9 changes: 9 additions & 0 deletions qttypes/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,15 @@ fn main() {
""
};

// MinGW and MSVC are not compatible
if cargo_target_os == "windows" {
let spec = qmake_query("QMAKE_SPEC");
if (spec.contains("msvc") && cargo_target_env == "gnu")
|| (spec.contains("g++") && cargo_target_env == "msvc")
{
report_error(&format!("Rust target '{}' is not compatible with Qt mkspec '{spec}'. Mixing MinGW and MSVC is not allowed.", std::env::var_os("TARGET").unwrap_or_default().to_string_lossy()));
}
}
if std::env::var("CARGO_CFG_TARGET_FAMILY").as_ref().map(|s| s.as_ref()) == Ok("unix") {
println!("cargo:rustc-cdylib-link-arg=-Wl,-rpath,{}", &qt_library_path);
}
Expand Down
4 changes: 2 additions & 2 deletions qttypes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ use internal_prelude::*;

mod qtcore;
pub use crate::qtcore::{
qreal, NormalizationForm, QByteArray, QListIterator, QString, QStringList, QUrl, QVariant,
QVariantList, UnicodeVersion,
qreal, NormalizationForm, QByteArray, QListIterator, QSettings, QString, QStringList, QUrl,
QVariant, QVariantList, UnicodeVersion,
};

mod qtgui;
Expand Down
2 changes: 2 additions & 0 deletions qttypes/src/qtcore/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod primitives;
mod qbytearray;
mod qchar;
mod qlist;
mod qsettings;
mod qstring;
mod qurl;
mod qvariant;
Expand All @@ -10,6 +11,7 @@ pub use self::primitives::qreal;
pub use self::qbytearray::QByteArray;
pub use self::qchar::UnicodeVersion;
pub use self::qlist::{QListIterator, QStringList, QVariantList};
pub use self::qsettings::QSettings;
pub use self::qstring::{NormalizationForm, QString};
pub use self::qurl::QUrl;
pub use self::qvariant::QVariant;
Loading

0 comments on commit 59029b9

Please sign in to comment.