From 2fc0f5c7f576c459c60af6bc5f76de51b3e03ef9 Mon Sep 17 00:00:00 2001 From: Adrian Date: Fri, 12 Nov 2021 19:57:08 +0100 Subject: [PATCH 01/14] Add wrappers around `QJsonValue`, `QJsonArray` and `QJsonObject` --- qmetaobject/src/qmetatype.rs | 3 + qttypes/src/lib.rs | 149 +++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+) diff --git a/qmetaobject/src/qmetatype.rs b/qmetaobject/src/qmetatype.rs index 3b487b24..7ec5a75b 100644 --- a/qmetaobject/src/qmetatype.rs +++ b/qmetaobject/src/qmetatype.rs @@ -488,6 +488,9 @@ impl QMetaType for QVariant { } } qdeclare_builtin_metatype! {QModelIndex => 42} +qdeclare_builtin_metatype! {QJsonValue => 45} +qdeclare_builtin_metatype! {QJsonObject => 46} +qdeclare_builtin_metatype! {QJsonArray => 47} qdeclare_builtin_metatype! {QPixmap => if cfg!(qt_6_0) { 0x1001 } else { 65 }} qdeclare_builtin_metatype! {QColor => if cfg!(qt_6_0) { 0x1003 } else { 67 }} qdeclare_builtin_metatype! {QImage => if cfg!(qt_6_0) { 0x1006 } else { 70 }} diff --git a/qttypes/src/lib.rs b/qttypes/src/lib.rs index 1da8609e..690fe324 100644 --- a/qttypes/src/lib.rs +++ b/qttypes/src/lib.rs @@ -126,6 +126,7 @@ use std::iter::FromIterator; use std::ops::{Index, IndexMut}; use std::os::raw::c_char; use std::str::Utf8Error; +use std::collections::HashMap; #[cfg(feature = "chrono")] use chrono::prelude::*; @@ -1769,3 +1770,151 @@ pub enum QPainterRenderHint { Qt4CompatiblePainting = 0x20, LosslessImageRendering = 0x40, } + +cpp! {{ + #include + #include + #include +}} +cpp_class!( + /// Wrapper around [`QJsonValue`][class] class. + /// + /// [class]: https://doc.qt.io/qt-5/qjsonvalue.html + #[derive(Default)] + pub unsafe struct QJsonValue as "QJsonValue" +); +impl Into for QJsonValue { + fn into(self) -> QVariant { + cpp!(unsafe [self as "QJsonValue"] -> QVariant as "QVariant" { + return self.toVariant(); + }) + } +} +impl From for QJsonValue { + fn from(v: QVariant) -> QJsonValue { + cpp!(unsafe [v as "QVariant"] -> QJsonValue as "QJsonValue" { + return QJsonValue::fromVariant(v); + }) + } +} + +impl From for QJsonValue { + fn from(v: QJsonObject) -> QJsonValue { + cpp!(unsafe [v as "QJsonObject"] -> QJsonValue as "QJsonValue" { + return QJsonValue(v); + }) + } +} +impl From for QJsonValue { + fn from(v: QJsonArray) -> QJsonValue { + cpp!(unsafe [v as "QJsonArray"] -> QJsonValue as "QJsonValue" { + return QJsonValue(v); + }) + } +} +impl From for QJsonValue { + fn from(v: QString) -> QJsonValue { + cpp!(unsafe [v as "QString"] -> QJsonValue as "QJsonValue" { + return QJsonValue(v); + }) + } +} +impl From for QJsonValue { + fn from(v: bool) -> QJsonValue { + cpp!(unsafe [v as "bool"] -> QJsonValue as "QJsonValue" { + return QJsonValue(v); + }) + } +} +impl From for QJsonValue { + fn from(v: i64) -> QJsonValue { + cpp!(unsafe [v as "qint64"] -> QJsonValue as "QJsonValue" { + return QJsonValue(v); + }) + } +} +impl From for QJsonValue { + fn from(v: f64) -> QJsonValue { + cpp!(unsafe [v as "double"] -> QJsonValue as "QJsonValue" { + return QJsonValue(v); + }) + } +} + +cpp_class!( + /// Wrapper around [`QJsonObject`][class] class. + /// + /// [class]: https://doc.qt.io/qt-5/qjsonobject.html + #[derive(Default)] + pub unsafe struct QJsonObject as "QJsonObject" +); + +impl From> for QJsonObject { + fn from(v: HashMap) -> QJsonObject { + let keys: Vec = v.keys().cloned().map(QString::from).collect(); + let values: Vec = v.into_values().map(QString::from).collect(); + let keys_ptr = keys.as_ptr(); + let values_ptr = values.as_ptr(); + let len = keys.len(); + cpp!(unsafe [keys_ptr as "const QString*", values_ptr as "const QString*", len as "size_t"] -> QJsonObject as "QJsonObject" { + QJsonObject obj; + for (size_t i = 0; i < len; ++i) { + obj.insert(keys_ptr[i], values_ptr[i]); + } + return obj; + }) + } +} +impl From> for QJsonObject { + fn from(v: HashMap) -> QJsonObject { + let keys: Vec = v.keys().cloned().map(QString::from).collect(); + let values: Vec = v.into_values().collect(); + let keys_ptr = keys.as_ptr(); + let values_ptr = values.as_ptr(); + let len = keys.len(); + cpp!(unsafe [keys_ptr as "const QString*", values_ptr as "const QJsonValue*", len as "size_t"] -> QJsonObject as "QJsonObject" { + QJsonObject obj; + for (size_t i = 0; i < len; ++i) { + obj.insert(keys_ptr[i], values_ptr[i]); + } + return obj; + }) + } +} + +impl From for QJsonObject { + fn from(v: QJsonValue) -> QJsonObject { + cpp!(unsafe [v as "QJsonValue"] -> QJsonObject as "QJsonObject" { + return v.toObject(); + }) + } +} +cpp_class!( + /// Wrapper around [`QJsonArray`][class] class. + /// + /// [class]: https://doc.qt.io/qt-5/qjsonarray.html + #[derive(Default)] + pub unsafe struct QJsonArray as "QJsonArray" +); + +impl From> for QJsonArray { + fn from(v: Vec) -> QJsonArray { + let ptr = v.as_ptr(); + let len = v.len(); + cpp!(unsafe [ptr as "const QJsonValue*", len as "size_t"] -> QJsonArray as "QJsonArray" { + QJsonArray arr; + for (size_t i = 0; i < len; ++i) { + arr.append(ptr[i]); + } + return arr; + }) + } +} + +impl From for QJsonArray { + fn from(v: QJsonValue) -> QJsonArray { + cpp!(unsafe [v as "QJsonValue"] -> QJsonArray as "QJsonArray" { + return v.toArray(); + }) + } +} From a9becb547c26d5f7a87260b477ad5ca822f8bb82 Mon Sep 17 00:00:00 2001 From: Adrian Date: Fri, 12 Nov 2021 20:11:24 +0100 Subject: [PATCH 02/14] Make it compile with older rustc than 1.56 --- qttypes/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qttypes/src/lib.rs b/qttypes/src/lib.rs index 690fe324..0e35de52 100644 --- a/qttypes/src/lib.rs +++ b/qttypes/src/lib.rs @@ -1852,7 +1852,7 @@ cpp_class!( impl From> for QJsonObject { fn from(v: HashMap) -> QJsonObject { let keys: Vec = v.keys().cloned().map(QString::from).collect(); - let values: Vec = v.into_values().map(QString::from).collect(); + let values: Vec = v.values().cloned().map(QString::from).collect(); let keys_ptr = keys.as_ptr(); let values_ptr = values.as_ptr(); let len = keys.len(); @@ -1868,7 +1868,7 @@ impl From> for QJsonObject { impl From> for QJsonObject { fn from(v: HashMap) -> QJsonObject { let keys: Vec = v.keys().cloned().map(QString::from).collect(); - let values: Vec = v.into_values().collect(); + let values: Vec = v.values().cloned().collect(); let keys_ptr = keys.as_ptr(); let values_ptr = values.as_ptr(); let len = keys.len(); From 50d97b45cdea91eef6ef1ccc2627073fb62d7cdd Mon Sep 17 00:00:00 2001 From: Adrian Date: Sun, 14 Nov 2021 18:59:03 +0100 Subject: [PATCH 03/14] Add more complete wrappers around QJson* types and add tests --- qttypes/src/lib.rs | 278 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 236 insertions(+), 42 deletions(-) diff --git a/qttypes/src/lib.rs b/qttypes/src/lib.rs index 0e35de52..172055aa 100644 --- a/qttypes/src/lib.rs +++ b/qttypes/src/lib.rs @@ -1772,72 +1772,135 @@ pub enum QPainterRenderHint { } cpp! {{ + #include + #include #include #include - #include }} cpp_class!( /// Wrapper around [`QJsonValue`][class] class. /// /// [class]: https://doc.qt.io/qt-5/qjsonvalue.html - #[derive(Default)] + #[derive(Default, PartialEq, Eq, Clone)] pub unsafe struct QJsonValue as "QJsonValue" ); + impl Into for QJsonValue { fn into(self) -> QVariant { - cpp!(unsafe [self as "QJsonValue"] -> QVariant as "QVariant" { - return self.toVariant(); - }) + cpp!(unsafe [self as "QJsonValue"] -> QVariant as "QVariant" { return self.toVariant(); }) } } impl From for QJsonValue { fn from(v: QVariant) -> QJsonValue { - cpp!(unsafe [v as "QVariant"] -> QJsonValue as "QJsonValue" { - return QJsonValue::fromVariant(v); - }) + cpp!(unsafe [v as "QVariant"] -> QJsonValue as "QJsonValue" { return QJsonValue::fromVariant(v); }) } } +impl Into for QJsonValue { + fn into(self) -> QJsonObject { + cpp!(unsafe [self as "QJsonValue"] -> QJsonObject as "QJsonObject" { return self.toObject(); }) + } +} impl From for QJsonValue { fn from(v: QJsonObject) -> QJsonValue { - cpp!(unsafe [v as "QJsonObject"] -> QJsonValue as "QJsonValue" { - return QJsonValue(v); - }) + cpp!(unsafe [v as "QJsonObject"] -> QJsonValue as "QJsonValue" { return QJsonValue(v); }) + } +} +impl Into for QJsonValue { + fn into(self) -> QJsonArray { + cpp!(unsafe [self as "QJsonValue"] -> QJsonArray as "QJsonArray" { return self.toArray(); }) } } impl From for QJsonValue { fn from(v: QJsonArray) -> QJsonValue { - cpp!(unsafe [v as "QJsonArray"] -> QJsonValue as "QJsonValue" { - return QJsonValue(v); - }) + cpp!(unsafe [v as "QJsonArray"] -> QJsonValue as "QJsonValue" { return QJsonValue(v); }) + } +} + +impl Into for QJsonValue { + fn into(self) -> QString { + cpp!(unsafe [self as "QJsonValue"] -> QString as "QString" { return self.toString(); }) } } impl From for QJsonValue { fn from(v: QString) -> QJsonValue { - cpp!(unsafe [v as "QString"] -> QJsonValue as "QJsonValue" { - return QJsonValue(v); - }) + cpp!(unsafe [v as "QString"] -> QJsonValue as "QJsonValue" { return QJsonValue(v); }) + } +} + +impl Into for QJsonValue { + fn into(self) -> bool { + cpp!(unsafe [self as "QJsonValue"] -> bool as "bool" { return self.toBool(); }) } } impl From for QJsonValue { fn from(v: bool) -> QJsonValue { - cpp!(unsafe [v as "bool"] -> QJsonValue as "QJsonValue" { - return QJsonValue(v); - }) + cpp!(unsafe [v as "bool"] -> QJsonValue as "QJsonValue" { return QJsonValue(v); }) } } -impl From for QJsonValue { - fn from(v: i64) -> QJsonValue { - cpp!(unsafe [v as "qint64"] -> QJsonValue as "QJsonValue" { - return QJsonValue(v); - }) + +impl Into for QJsonValue { + fn into(self) -> f64 { + cpp!(unsafe [self as "QJsonValue"] -> f64 as "double" { return self.toDouble(); }) } } impl From for QJsonValue { fn from(v: f64) -> QJsonValue { - cpp!(unsafe [v as "double"] -> QJsonValue as "QJsonValue" { - return QJsonValue(v); - }) + cpp!(unsafe [v as "double"] -> QJsonValue as "QJsonValue" { return QJsonValue(v); }) + } +} + +#[test] +fn test_qjsonvalue() { + let test_str = QJsonValue::from(QVariant::from(QString::from("test"))); + let test_str2 = QJsonValue::from(QString::from("test")); + assert!(test_str == test_str2); + assert_eq!(>::into(test_str), QString::from("test")); + + let test_bool = QJsonValue::from(true); + let test_bool_variant: QVariant = QJsonValue::from(true).into(); + let test_bool_variant2 = QVariant::from(true); + assert!(test_bool_variant == test_bool_variant2); + assert_eq!(>::into(test_bool), true); + + let test_f64 = QJsonValue::from(1.2345); + let test_f64_variant: QVariant = QJsonValue::from(1.2345).into(); + let test_f64_variant2 = QVariant::from(1.2345); + assert!(test_f64_variant == test_f64_variant2); + assert_eq!(>::into(test_f64), 1.2345); + + let values = QJsonArray::from(vec![ + QJsonValue::from(QString::from("test")), + QJsonValue::from(true), + QJsonValue::from(false), + QJsonValue::from(1.2345), + QJsonValue::from(456.0), + ]); + + assert_eq!(values.to_json().to_string(), "[\"test\",true,false,1.2345,456]"); +} + +cpp_class!( + /// Wrapper around [`QStringList`][class] class. + /// + /// [class]: https://doc.qt.io/qt-5/qstringlist.html + #[derive(Default, Clone)] + pub unsafe struct QStringList as "QStringList" +); +impl QStringList { + pub fn len(&self) -> usize { + cpp!(unsafe [self as "QStringList*"] -> usize as "size_t" { return self->size(); }) + } +} +impl Index for QStringList { + type Output = QString; + + fn index(&self, index: usize) -> &QString { + unsafe { + &*cpp!([self as "QStringList*", index as "size_t"] -> *const QString as "const QString*" { + return &(*self)[index]; + }) + } } } @@ -1845,10 +1908,61 @@ cpp_class!( /// Wrapper around [`QJsonObject`][class] class. /// /// [class]: https://doc.qt.io/qt-5/qjsonobject.html - #[derive(Default)] + #[derive(Default, PartialEq, Eq, Clone)] pub unsafe struct QJsonObject as "QJsonObject" ); +impl QJsonObject { + pub fn to_json(&self) -> QByteArray { + cpp!(unsafe [self as "QJsonObject*"] -> QByteArray as "QByteArray" { return QJsonDocument(*self).toJson(QJsonDocument::Compact); }) + } + pub fn to_json_pretty(&self) -> QByteArray { + cpp!(unsafe [self as "QJsonObject*"] -> QByteArray as "QByteArray" { return QJsonDocument(*self).toJson(QJsonDocument::Indented); }) + } + pub fn insert(&mut self, key: &str, value: QJsonValue) { + let len = key.len(); + let ptr = key.as_ptr(); + cpp!(unsafe [self as "QJsonObject*", len as "size_t", ptr as "char*", value as "QJsonValue"] { self->insert(QLatin1String(ptr, len), std::move(value)); }) + } + pub fn value(&self, key: &str) -> QJsonValue { + let len = key.len(); + let ptr = key.as_ptr(); + cpp!(unsafe [self as "QJsonObject*", len as "size_t", ptr as "char*"] -> QJsonValue as "QJsonValue" { return self->value(QLatin1String(ptr, len)); }) + } + pub fn take(&mut self, key: &str) -> QJsonValue { + let len = key.len(); + let ptr = key.as_ptr(); + cpp!(unsafe [self as "QJsonObject*", len as "size_t", ptr as "char*"] -> QJsonValue as "QJsonValue" { return self->take(QLatin1String(ptr, len)); }) + } + pub fn remove(&mut self, key: &str) { + let len = key.len(); + let ptr = key.as_ptr(); + cpp!(unsafe [self as "QJsonObject*", len as "size_t", ptr as "char*"] { return self->remove(QLatin1String(ptr, len)); }) + } + pub fn len(&self) -> usize { + cpp!(unsafe [self as "QJsonObject*"] -> usize as "size_t" { return self->size(); }) + } + pub fn is_empty(&self) -> bool { + cpp!(unsafe [self as "QJsonObject*"] -> bool as "bool" { return self->isEmpty(); }) + } + pub fn contains(&self, key: &str) -> bool { + let len = key.len(); + let ptr = key.as_ptr(); + cpp!(unsafe [self as "QJsonObject*", len as "size_t", ptr as "char*"] -> bool as "bool" { return self->contains(QLatin1String(ptr, len)); }) + } + pub fn keys(&self) -> Vec { + let len = self.len(); + let mut vec = Vec::with_capacity(len); + + let keys = cpp!(unsafe [self as "QJsonObject*"] -> QStringList as "QStringList" { return self->keys(); }); + + for i in 0..len { + vec.push(keys[i].to_string()); + } + vec + } +} + impl From> for QJsonObject { fn from(v: HashMap) -> QJsonObject { let keys: Vec = v.keys().cloned().map(QString::from).collect(); @@ -1882,21 +1996,87 @@ impl From> for QJsonObject { } } -impl From for QJsonObject { - fn from(v: QJsonValue) -> QJsonObject { - cpp!(unsafe [v as "QJsonValue"] -> QJsonObject as "QJsonObject" { - return v.toObject(); - }) - } +cpp! {{ #include }} + +#[test] +fn test_qjsonobject() { + let mut hashmap = HashMap::new(); + hashmap.insert("key".to_owned(), "value".to_owned()); + hashmap.insert("test".to_owned(), "hello".to_owned()); + let object = QJsonObject::from(hashmap); + assert_eq!(object.to_json().to_string(), "{\"key\":\"value\",\"test\":\"hello\"}"); + + + let array = QJsonArray::from(vec![ + QJsonValue::from(QString::from("test")), + QJsonValue::from(true), + QJsonValue::from(false), + QJsonValue::from(1.2345), + QJsonValue::from(456.0), + ]); + + let mut valuemap = HashMap::new(); + valuemap.insert("1_string".to_owned(), QJsonValue::from(QString::from("test"))); + valuemap.insert("2_bool".to_owned(), QJsonValue::from(true)); + valuemap.insert("3_f64".to_owned(), QJsonValue::from(1.2345)); + valuemap.insert("4_int".to_owned(), QJsonValue::from(456.0)); + valuemap.insert("5_array".to_owned(), QJsonValue::from(array)); + valuemap.insert("6_object".to_owned(), QJsonValue::from(object)); + let object = QJsonObject::from(valuemap); + assert_eq!(object.to_json().to_string(), "{\"1_string\":\"test\",\"2_bool\":true,\"3_f64\":1.2345,\"4_int\":456,\"5_array\":[\"test\",true,false,1.2345,456],\"6_object\":{\"key\":\"value\",\"test\":\"hello\"}}"); + + let at_f64: f64 = object.value("3_f64").into(); + assert_eq!(at_f64, 1.2345); + + let at_string = object.value("1_string"); + assert_eq!(>::into(at_string).to_string(), "test"); + + let mut object = QJsonObject::default(); + object.insert("key", QJsonValue::from(QString::from("value"))); + object.insert("test", QJsonValue::from(QString::from("hello"))); + assert_eq!(object.to_json().to_string(), "{\"key\":\"value\",\"test\":\"hello\"}"); + + assert_eq!(object.keys(), vec!["key".to_owned(), "test".to_owned()]); } + cpp_class!( /// Wrapper around [`QJsonArray`][class] class. /// /// [class]: https://doc.qt.io/qt-5/qjsonarray.html - #[derive(Default)] + #[derive(Default, PartialEq, Eq, Clone)] pub unsafe struct QJsonArray as "QJsonArray" ); +impl QJsonArray { + pub fn to_json(&self) -> QByteArray { + cpp!(unsafe [self as "QJsonArray*"] -> QByteArray as "QByteArray" { return QJsonDocument(*self).toJson(QJsonDocument::Compact); }) + } + pub fn to_json_pretty(&self) -> QByteArray { + cpp!(unsafe [self as "QJsonArray*"] -> QByteArray as "QByteArray" { return QJsonDocument(*self).toJson(QJsonDocument::Indented); }) + } + pub fn push(&mut self, value: QJsonValue) { + cpp!(unsafe [self as "QJsonArray*", value as "QJsonValue"] { self->append(std::move(value)); }) + } + pub fn insert(&mut self, index: usize, element: QJsonValue) { + cpp!(unsafe [self as "QJsonArray*", index as "size_t", element as "QJsonValue"] { self->insert(index, std::move(element)); }) + } + pub fn at(&self, index: usize) -> QJsonValue { + cpp!(unsafe [self as "QJsonArray*", index as "size_t"] -> QJsonValue as "QJsonValue" { return self->at(index); }) + } + pub fn take_at(&mut self, index: usize) -> QJsonValue { + cpp!(unsafe [self as "QJsonArray*", index as "size_t"] -> QJsonValue as "QJsonValue" { return self->takeAt(index); }) + } + pub fn remove_at(&mut self, index: usize) { + cpp!(unsafe [self as "QJsonArray*", index as "size_t"] { return self->removeAt(index); }) + } + pub fn len(&self) -> usize { + cpp!(unsafe [self as "QJsonArray*"] -> usize as "size_t" { return self->size(); }) + } + pub fn is_empty(&self) -> bool { + cpp!(unsafe [self as "QJsonArray*"] -> bool as "bool" { return self->isEmpty(); }) + } +} + impl From> for QJsonArray { fn from(v: Vec) -> QJsonArray { let ptr = v.as_ptr(); @@ -1911,10 +2091,24 @@ impl From> for QJsonArray { } } -impl From for QJsonArray { - fn from(v: QJsonValue) -> QJsonArray { - cpp!(unsafe [v as "QJsonValue"] -> QJsonArray as "QJsonArray" { - return v.toArray(); - }) - } +#[test] +fn test_qjsonarray() { + let mut array = QJsonArray::default(); + array.push(QJsonValue::from(QString::from("test"))); + array.push(QJsonValue::from(true)); + array.push(QJsonValue::from(false)); + array.push(QJsonValue::from(1.2345)); + assert_eq!(array.to_json().to_string(), "[\"test\",true,false,1.2345]"); + + let mut vec = Vec::new(); + vec.push(QJsonValue::from(QString::from("test"))); + vec.push(QJsonValue::from(true)); + vec.push(QJsonValue::from(false)); + vec.push(QJsonValue::from(1.2345)); + assert!(QJsonArray::from(vec) == array); + + assert_eq!(array.len(), 4); + + assert_eq!(>::into(array.at(0)).to_string(), "test"); + assert!(array.at(3) == QJsonValue::from(1.2345)); } From 3f52a88af355b22cd08bf0a8573c81b49c4f49e9 Mon Sep 17 00:00:00 2001 From: Adrian Date: Mon, 15 Nov 2021 10:05:13 +0100 Subject: [PATCH 04/14] Add a feature to skip linking with QtWidgets and use `QGuiApplication` instead of `QApplication` --- qmetaobject/Cargo.toml | 1 + qmetaobject/src/qtdeclarative.rs | 16 +++++++++++++--- qttypes/Cargo.toml | 2 ++ qttypes/build.rs | 1 + 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/qmetaobject/Cargo.toml b/qmetaobject/Cargo.toml index eebfe3e2..d5339e5f 100644 --- a/qmetaobject/Cargo.toml +++ b/qmetaobject/Cargo.toml @@ -15,6 +15,7 @@ repository = "https://github.com/woboq/qmetaobject-rs" default = ["log"] chrono_qdatetime = ["qttypes/chrono"] webengine = ["qttypes/qtwebengine"] +nowidgets = ["qttypes/nowidgets"] [dependencies] qttypes = { path = "../qttypes", version = "0.2.4", features = ["qtquick"] } diff --git a/qmetaobject/src/qtdeclarative.rs b/qmetaobject/src/qtdeclarative.rs index 0f232fde..934bf396 100644 --- a/qmetaobject/src/qtdeclarative.rs +++ b/qmetaobject/src/qtdeclarative.rs @@ -24,11 +24,21 @@ use crate::*; /// So this is a guard that will be used to panic if the engine is created twice static HAS_ENGINE: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); +#[cfg(feature = "nowidgets")] +cpp! {{ + #include + #define QAPPLICATION QGuiApplication +}} +#[cfg(not(feature = "nowidgets"))] +cpp! {{ + #include + #define QAPPLICATION QApplication +}} + cpp! {{ #include #include #include - #include #include struct SingleApplicationGuard { @@ -47,12 +57,12 @@ cpp! {{ }; struct QmlEngineHolder : SingleApplicationGuard { - std::unique_ptr app; + std::unique_ptr app; std::unique_ptr engine; std::unique_ptr view; QmlEngineHolder(int &argc, char **argv) - : app(new QApplication(argc, argv)) + : app(new QAPPLICATION(argc, argv)) , engine(new QQmlApplicationEngine()) {} }; diff --git a/qttypes/Cargo.toml b/qttypes/Cargo.toml index d2b2f204..e0bf4460 100644 --- a/qttypes/Cargo.toml +++ b/qttypes/Cargo.toml @@ -31,6 +31,8 @@ qtmultimediawidgets = [] qtsql = [] # Link against QtTest qttest = [] +# Don't link QtWidgets and use QGuiApplication +nowidgets = [] default = ["required"] diff --git a/qttypes/build.rs b/qttypes/build.rs index d489ee45..7c5a0036 100644 --- a/qttypes/build.rs +++ b/qttypes/build.rs @@ -201,6 +201,7 @@ fn main() { }; link_lib("Core"); link_lib("Gui"); + #[cfg(not(feature = "nowidgets"))] link_lib("Widgets"); #[cfg(feature = "qtquick")] link_lib("Quick"); From 5dfc6c9f1b4ead1acde96e837cc2bfc1438a10a0 Mon Sep 17 00:00:00 2001 From: Adrian Date: Mon, 15 Nov 2021 10:33:10 +0100 Subject: [PATCH 05/14] Fix build with QtWebEngine and add docs --- README.md | 6 ++++++ qmetaobject/src/lib.rs | 1 + qttypes/build.rs | 4 +++- qttypes/src/lib.rs | 1 + 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 234fae8b..bd774370 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,12 @@ Enables `QtWebEngine` functionality. For more details see the [example](./exampl This feature is disabled by default. +### `nowidgets` + +Don't link against **`qtwidgets`** module. This will use `QGuiApplication` instead of `QApplcation`. + +This feature is disabled by default. + ## What if a wrapper for the Qt C++ API is missing? It is quite likely that you would like to call a particular Qt function which diff --git a/qmetaobject/src/lib.rs b/qmetaobject/src/lib.rs index 56ad01c3..8f8aa686 100644 --- a/qmetaobject/src/lib.rs +++ b/qmetaobject/src/lib.rs @@ -208,6 +208,7 @@ pub mod qtquickcontrols2; pub mod scenegraph; pub mod tablemodel; #[cfg(feature = "webengine")] +#[cfg(not(feature = "nowidgets"))] #[cfg(not(any(qt_6_0, qt_6_1)))] #[cfg(not(all(target_os = "windows", not(target_env = "msvc"))))] pub mod webengine; diff --git a/qttypes/build.rs b/qttypes/build.rs index 7c5a0036..ff59fd61 100644 --- a/qttypes/build.rs +++ b/qttypes/build.rs @@ -207,7 +207,8 @@ fn main() { link_lib("Quick"); #[cfg(feature = "qtquick")] link_lib("Qml"); - #[cfg(feature = "qtwebengine")] + #[cfg(feature = "webengine")] + #[cfg(not(feature = "nowidgets"))] if qt_version >= Version::new(6, 0, 0) && qt_version < Version::new(6, 2, 0) { println!("cargo:warning=WebEngine is not supported on Qt {} yet. It is planned for Qt 6.2 LTS.", qt_version); } else if (cargo_target_os == "windows") && (cargo_target_env != "msvc") { @@ -220,6 +221,7 @@ fn main() { #[cfg(feature = "qtmultimedia")] link_lib("Multimedia"); #[cfg(feature = "qtmultimediawidgets")] + #[cfg(not(feature = "nowidgets"))] link_lib("MultimediaWidgets"); #[cfg(feature = "qtsql")] link_lib("Sql"); diff --git a/qttypes/src/lib.rs b/qttypes/src/lib.rs index 172055aa..21c28516 100644 --- a/qttypes/src/lib.rs +++ b/qttypes/src/lib.rs @@ -104,6 +104,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //! if Qt is not found. Otherwise, when not enabled, the build will continue, but any use of the classes will //! panic at runtime. //! - **`chrono`**: enable the conversion between [`QDateTime`] related types and the types from the `chrono` crate. +//! - **`nowidgets`**: Don't link against **`qtwidgets`** module. This will use `QGuiApplication` instead of `QApplcation`. //! //! Link against these Qt modules using cargo features: //! From 1af5a5f9d8741f103fd2afa9d519db669fcd9e61 Mon Sep 17 00:00:00 2001 From: Adrian Date: Mon, 15 Nov 2021 10:33:50 +0100 Subject: [PATCH 06/14] Fix build --- qmetaobject/src/qtdeclarative.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/qmetaobject/src/qtdeclarative.rs b/qmetaobject/src/qtdeclarative.rs index 934bf396..93f2b78e 100644 --- a/qmetaobject/src/qtdeclarative.rs +++ b/qmetaobject/src/qtdeclarative.rs @@ -24,16 +24,16 @@ use crate::*; /// So this is a guard that will be used to panic if the engine is created twice static HAS_ENGINE: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); -#[cfg(feature = "nowidgets")] -cpp! {{ - #include - #define QAPPLICATION QGuiApplication -}} #[cfg(not(feature = "nowidgets"))] cpp! {{ #include #define QAPPLICATION QApplication }} +#[cfg(feature = "nowidgets")] +cpp! {{ + #include + #define QAPPLICATION QGuiApplication +}} cpp! {{ #include From 449457188d67bc0ccd1fd1b8caa695f7dea1c4f5 Mon Sep 17 00:00:00 2001 From: Adrian Date: Mon, 15 Nov 2021 10:36:26 +0100 Subject: [PATCH 07/14] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bd774370..334a7479 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ This feature is disabled by default. ### `nowidgets` -Don't link against **`qtwidgets`** module. This will use `QGuiApplication` instead of `QApplcation`. +Don't link against **`qtwidgets`** module. This will use `QGuiApplication` instead of `QApplication`. This feature is disabled by default. From 8021f2a81505ee8bd2bc5ad3825f8559e1f9e8b6 Mon Sep 17 00:00:00 2001 From: Adrian Date: Mon, 15 Nov 2021 12:02:15 +0100 Subject: [PATCH 08/14] Update to additive feature --- README.md | 6 +++--- qmetaobject/Cargo.toml | 4 ++-- qmetaobject/src/lib.rs | 2 +- qmetaobject/src/qtdeclarative.rs | 4 ++-- qttypes/Cargo.toml | 6 +++--- qttypes/build.rs | 8 +++----- qttypes/src/lib.rs | 2 +- 7 files changed, 15 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 334a7479..f5cd4bcf 100644 --- a/README.md +++ b/README.md @@ -108,11 +108,11 @@ Enables `QtWebEngine` functionality. For more details see the [example](./exampl This feature is disabled by default. -### `nowidgets` +### `widgets` -Don't link against **`qtwidgets`** module. This will use `QGuiApplication` instead of `QApplication`. +Link against **`qtwidgets`** module. This will use `QApplication` instead of `QGuiApplication`. -This feature is disabled by default. +This feature is enabled by default and is required for `webengine` feature. ## What if a wrapper for the Qt C++ API is missing? diff --git a/qmetaobject/Cargo.toml b/qmetaobject/Cargo.toml index d5339e5f..4127b843 100644 --- a/qmetaobject/Cargo.toml +++ b/qmetaobject/Cargo.toml @@ -12,10 +12,10 @@ keywords = ["Qt", "QML", "QMetaObject",] repository = "https://github.com/woboq/qmetaobject-rs" [features] -default = ["log"] +default = ["log", "widgets"] chrono_qdatetime = ["qttypes/chrono"] webengine = ["qttypes/qtwebengine"] -nowidgets = ["qttypes/nowidgets"] +widgets = ["qttypes/qtwidgets"] [dependencies] qttypes = { path = "../qttypes", version = "0.2.4", features = ["qtquick"] } diff --git a/qmetaobject/src/lib.rs b/qmetaobject/src/lib.rs index 8f8aa686..9dd95bf3 100644 --- a/qmetaobject/src/lib.rs +++ b/qmetaobject/src/lib.rs @@ -208,7 +208,7 @@ pub mod qtquickcontrols2; pub mod scenegraph; pub mod tablemodel; #[cfg(feature = "webengine")] -#[cfg(not(feature = "nowidgets"))] +#[cfg(feature = "widgets")] #[cfg(not(any(qt_6_0, qt_6_1)))] #[cfg(not(all(target_os = "windows", not(target_env = "msvc"))))] pub mod webengine; diff --git a/qmetaobject/src/qtdeclarative.rs b/qmetaobject/src/qtdeclarative.rs index 93f2b78e..36ce65d3 100644 --- a/qmetaobject/src/qtdeclarative.rs +++ b/qmetaobject/src/qtdeclarative.rs @@ -24,12 +24,12 @@ use crate::*; /// So this is a guard that will be used to panic if the engine is created twice static HAS_ENGINE: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); -#[cfg(not(feature = "nowidgets"))] +#[cfg(feature = "widgets")] cpp! {{ #include #define QAPPLICATION QApplication }} -#[cfg(feature = "nowidgets")] +#[cfg(not(feature = "widgets"))] cpp! {{ #include #define QAPPLICATION QGuiApplication diff --git a/qttypes/Cargo.toml b/qttypes/Cargo.toml index e0bf4460..e5aa7401 100644 --- a/qttypes/Cargo.toml +++ b/qttypes/Cargo.toml @@ -31,10 +31,10 @@ qtmultimediawidgets = [] qtsql = [] # Link against QtTest qttest = [] -# Don't link QtWidgets and use QGuiApplication -nowidgets = [] +# Link against QtWidgets +qtwidgets = [] -default = ["required"] +default = ["required", "qtwidgets"] [dependencies] cpp = "0.5.6" diff --git a/qttypes/build.rs b/qttypes/build.rs index ff59fd61..9df5fef4 100644 --- a/qttypes/build.rs +++ b/qttypes/build.rs @@ -201,14 +201,13 @@ fn main() { }; link_lib("Core"); link_lib("Gui"); - #[cfg(not(feature = "nowidgets"))] + #[cfg(feature = "qtwidgets")] link_lib("Widgets"); #[cfg(feature = "qtquick")] link_lib("Quick"); #[cfg(feature = "qtquick")] link_lib("Qml"); - #[cfg(feature = "webengine")] - #[cfg(not(feature = "nowidgets"))] + #[cfg(all(feature = "qtwebengine", feature = "qtwidgets"))] if qt_version >= Version::new(6, 0, 0) && qt_version < Version::new(6, 2, 0) { println!("cargo:warning=WebEngine is not supported on Qt {} yet. It is planned for Qt 6.2 LTS.", qt_version); } else if (cargo_target_os == "windows") && (cargo_target_env != "msvc") { @@ -220,8 +219,7 @@ fn main() { link_lib("QuickControls2"); #[cfg(feature = "qtmultimedia")] link_lib("Multimedia"); - #[cfg(feature = "qtmultimediawidgets")] - #[cfg(not(feature = "nowidgets"))] + #[cfg(all(feature = "qtmultimediawidgets", feature = "qtwidgets"))] link_lib("MultimediaWidgets"); #[cfg(feature = "qtsql")] link_lib("Sql"); diff --git a/qttypes/src/lib.rs b/qttypes/src/lib.rs index 21c28516..32eec872 100644 --- a/qttypes/src/lib.rs +++ b/qttypes/src/lib.rs @@ -104,7 +104,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //! if Qt is not found. Otherwise, when not enabled, the build will continue, but any use of the classes will //! panic at runtime. //! - **`chrono`**: enable the conversion between [`QDateTime`] related types and the types from the `chrono` crate. -//! - **`nowidgets`**: Don't link against **`qtwidgets`** module. This will use `QGuiApplication` instead of `QApplcation`. //! //! Link against these Qt modules using cargo features: //! @@ -117,6 +116,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //! | **`qtsql`** | Qt SQL | //! | **`qttest`** | Qt Test | //! | **`qtwebengine`** | Qt WebEngine | +//! | **`qtwidgets`** | Qt Widgets | //! #![cfg_attr(no_qt, allow(unused))] From dba9a3a331c5355d660f705a864cd942f263c1af Mon Sep 17 00:00:00 2001 From: Adrian Date: Mon, 15 Nov 2021 15:21:06 +0100 Subject: [PATCH 09/14] Add a define to build.rs and use #ifdef --- README.md | 2 +- qmetaobject/build.rs | 3 +++ qmetaobject/src/lib.rs | 1 - qmetaobject/src/qtdeclarative.rs | 19 ++++++++----------- qttypes/build.rs | 2 +- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index f5cd4bcf..e9e4bc98 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ This feature is disabled by default. Link against **`qtwidgets`** module. This will use `QApplication` instead of `QGuiApplication`. -This feature is enabled by default and is required for `webengine` feature. +This feature is enabled by default. ## What if a wrapper for the Qt C++ API is missing? diff --git a/qmetaobject/build.rs b/qmetaobject/build.rs index 950a946d..92f585ea 100644 --- a/qmetaobject/build.rs +++ b/qmetaobject/build.rs @@ -33,6 +33,9 @@ fn main() { config.flag("-F"); config.flag(&qt_library_path); } + if cfg!(not(feature = "widgets")) { + config.flag("-DNO_WIDGETS"); + } if qt_version >= Version::new(6, 0, 0) { config.flag_if_supported("-std=c++17"); config.flag_if_supported("/std:c++17"); diff --git a/qmetaobject/src/lib.rs b/qmetaobject/src/lib.rs index 9dd95bf3..56ad01c3 100644 --- a/qmetaobject/src/lib.rs +++ b/qmetaobject/src/lib.rs @@ -208,7 +208,6 @@ pub mod qtquickcontrols2; pub mod scenegraph; pub mod tablemodel; #[cfg(feature = "webengine")] -#[cfg(feature = "widgets")] #[cfg(not(any(qt_6_0, qt_6_1)))] #[cfg(not(all(target_os = "windows", not(target_env = "msvc"))))] pub mod webengine; diff --git a/qmetaobject/src/qtdeclarative.rs b/qmetaobject/src/qtdeclarative.rs index 36ce65d3..81c6b119 100644 --- a/qmetaobject/src/qtdeclarative.rs +++ b/qmetaobject/src/qtdeclarative.rs @@ -24,22 +24,19 @@ use crate::*; /// So this is a guard that will be used to panic if the engine is created twice static HAS_ENGINE: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); -#[cfg(feature = "widgets")] -cpp! {{ - #include - #define QAPPLICATION QApplication -}} -#[cfg(not(feature = "widgets"))] -cpp! {{ - #include - #define QAPPLICATION QGuiApplication -}} - cpp! {{ #include #include #include #include + + #ifdef NO_WIDGETS + # define QAPPLICATION QGuiApplication + # include + #else + # define QAPPLICATION QApplication + # include + #endif struct SingleApplicationGuard { SingleApplicationGuard() { diff --git a/qttypes/build.rs b/qttypes/build.rs index 9df5fef4..d09050dd 100644 --- a/qttypes/build.rs +++ b/qttypes/build.rs @@ -207,7 +207,7 @@ fn main() { link_lib("Quick"); #[cfg(feature = "qtquick")] link_lib("Qml"); - #[cfg(all(feature = "qtwebengine", feature = "qtwidgets"))] + #[cfg(feature = "qtwebengine")] if qt_version >= Version::new(6, 0, 0) && qt_version < Version::new(6, 2, 0) { println!("cargo:warning=WebEngine is not supported on Qt {} yet. It is planned for Qt 6.2 LTS.", qt_version); } else if (cargo_target_os == "windows") && (cargo_target_env != "msvc") { From 2d239bdd71b793b59662f252663413dd8a2170e5 Mon Sep 17 00:00:00 2001 From: Adrian Date: Tue, 16 Nov 2021 10:39:40 +0100 Subject: [PATCH 10/14] Minor updates --- qmetaobject/build.rs | 2 +- qttypes/Cargo.toml | 2 +- qttypes/build.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/qmetaobject/build.rs b/qmetaobject/build.rs index 92f585ea..41e6147f 100644 --- a/qmetaobject/build.rs +++ b/qmetaobject/build.rs @@ -34,7 +34,7 @@ fn main() { config.flag(&qt_library_path); } if cfg!(not(feature = "widgets")) { - config.flag("-DNO_WIDGETS"); + config.define("NO_WIDGETS", None); } if qt_version >= Version::new(6, 0, 0) { config.flag_if_supported("-std=c++17"); diff --git a/qttypes/Cargo.toml b/qttypes/Cargo.toml index e5aa7401..3aafae0f 100644 --- a/qttypes/Cargo.toml +++ b/qttypes/Cargo.toml @@ -26,7 +26,7 @@ qtquickcontrols2 = [] # Link against QtMultimedia qtmultimedia = [] # Link against QtMultimediaWidgets -qtmultimediawidgets = [] +qtmultimediawidgets = ["qtwidgets"] # Link against QtSql qtsql = [] # Link against QtTest diff --git a/qttypes/build.rs b/qttypes/build.rs index d09050dd..b6930dfa 100644 --- a/qttypes/build.rs +++ b/qttypes/build.rs @@ -219,7 +219,7 @@ fn main() { link_lib("QuickControls2"); #[cfg(feature = "qtmultimedia")] link_lib("Multimedia"); - #[cfg(all(feature = "qtmultimediawidgets", feature = "qtwidgets"))] + #[cfg(feature = "qtmultimediawidgets")] link_lib("MultimediaWidgets"); #[cfg(feature = "qtsql")] link_lib("Sql"); From e359084fda52dadf6851fda1f5a0d9305543277a Mon Sep 17 00:00:00 2001 From: Adrian Date: Sun, 30 Jan 2022 10:43:06 +0100 Subject: [PATCH 11/14] Fix building on Android. For some reason `-std=c++17` is not detected as supported, but it's required on Android so add it explicitly --- README.md | 6 ------ qmetaobject/Cargo.toml | 3 +-- qmetaobject/build.rs | 9 +++++---- qmetaobject/src/qtdeclarative.rs | 13 +++---------- qttypes/Cargo.toml | 6 ++---- qttypes/build.rs | 7 +++++-- qttypes/src/lib.rs | 1 - 7 files changed, 16 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 39ab46c9..058ee542 100644 --- a/README.md +++ b/README.md @@ -107,12 +107,6 @@ Enables `QtWebEngine` functionality. For more details see the [example](./exampl This feature is disabled by default. -### `widgets` - -Link against **`qtwidgets`** module. This will use `QApplication` instead of `QGuiApplication`. - -This feature is enabled by default. - ## What if a wrapper for the Qt C++ API is missing? It is quite likely that you would like to call a particular Qt function which diff --git a/qmetaobject/Cargo.toml b/qmetaobject/Cargo.toml index 9e38e913..02d6314b 100644 --- a/qmetaobject/Cargo.toml +++ b/qmetaobject/Cargo.toml @@ -12,10 +12,9 @@ keywords = ["Qt", "QML", "QMetaObject",] repository = "https://github.com/woboq/qmetaobject-rs" [features] -default = ["log", "widgets"] +default = ["log"] chrono_qdatetime = ["qttypes/chrono"] webengine = ["qttypes/qtwebengine"] -widgets = ["qttypes/qtwidgets"] [dependencies] qttypes = { path = "../qttypes", version = "0.2.5", features = ["qtquick"] } diff --git a/qmetaobject/build.rs b/qmetaobject/build.rs index 41e6147f..c0d3ddd1 100644 --- a/qmetaobject/build.rs +++ b/qmetaobject/build.rs @@ -33,11 +33,12 @@ fn main() { config.flag("-F"); config.flag(&qt_library_path); } - if cfg!(not(feature = "widgets")) { - config.define("NO_WIDGETS", None); - } if qt_version >= Version::new(6, 0, 0) { - config.flag_if_supported("-std=c++17"); + if std::env::var("CARGO_CFG_TARGET_OS").unwrap() == "android" { + config.flag("-std=c++17"); + } else { + config.flag_if_supported("-std=c++17"); + } config.flag_if_supported("/std:c++17"); config.flag_if_supported("/Zc:__cplusplus"); } diff --git a/qmetaobject/src/qtdeclarative.rs b/qmetaobject/src/qtdeclarative.rs index 75d13fd0..397bfa64 100644 --- a/qmetaobject/src/qtdeclarative.rs +++ b/qmetaobject/src/qtdeclarative.rs @@ -28,15 +28,8 @@ cpp! {{ #include #include #include + #include #include - - #ifdef NO_WIDGETS - # define QAPPLICATION QGuiApplication - # include - #else - # define QAPPLICATION QApplication - # include - #endif struct SingleApplicationGuard { SingleApplicationGuard() { @@ -54,12 +47,12 @@ cpp! {{ }; struct QmlEngineHolder : SingleApplicationGuard { - std::unique_ptr app; + std::unique_ptr app; std::unique_ptr engine; std::unique_ptr view; QmlEngineHolder(int &argc, char **argv) - : app(new QAPPLICATION(argc, argv)) + : app(new QApplication(argc, argv)) , engine(new QQmlApplicationEngine()) {} }; diff --git a/qttypes/Cargo.toml b/qttypes/Cargo.toml index 49ce1976..e5ca4764 100644 --- a/qttypes/Cargo.toml +++ b/qttypes/Cargo.toml @@ -27,15 +27,13 @@ qtquickcontrols2 = [] # Link against QtMultimedia qtmultimedia = [] # Link against QtMultimediaWidgets -qtmultimediawidgets = ["qtwidgets"] +qtmultimediawidgets = [] # Link against QtSql qtsql = [] # Link against QtTest qttest = [] -# Link against QtWidgets -qtwidgets = [] -default = ["required", "qtwidgets"] +default = ["required"] [dependencies] cpp = "0.5.6" diff --git a/qttypes/build.rs b/qttypes/build.rs index fdf3d01a..203e71e8 100644 --- a/qttypes/build.rs +++ b/qttypes/build.rs @@ -167,7 +167,11 @@ fn main() { detect_qreal_size(&qt_include_path, &qt_library_path); if qt_version >= Version::new(6, 0, 0) { - config.flag_if_supported("-std=c++17"); + if std::env::var("CARGO_CFG_TARGET_OS").unwrap() == "android" { + config.flag("-std=c++17"); + } else { + config.flag_if_supported("-std=c++17"); + } config.flag_if_supported("/std:c++17"); config.flag_if_supported("/Zc:__cplusplus"); } @@ -209,7 +213,6 @@ fn main() { }; link_lib("Core"); link_lib("Gui"); - #[cfg(feature = "qtwidgets")] link_lib("Widgets"); #[cfg(feature = "qtquick")] link_lib("Quick"); diff --git a/qttypes/src/lib.rs b/qttypes/src/lib.rs index 71e034a1..a42ad95c 100644 --- a/qttypes/src/lib.rs +++ b/qttypes/src/lib.rs @@ -116,7 +116,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //! | **`qtsql`** | Qt SQL | //! | **`qttest`** | Qt Test | //! | **`qtwebengine`** | Qt WebEngine | -//! | **`qtwidgets`** | Qt Widgets | //! #![cfg_attr(no_qt, allow(unused))] From a287bb1aec60ba3f7b50476915981eab9b48702b Mon Sep 17 00:00:00 2001 From: Adrian Date: Sun, 30 Jan 2022 10:49:13 +0100 Subject: [PATCH 12/14] Revert "Fix building on Android. For some reason `-std=c++17` is not detected as supported, but it's required on Android so add it explicitly" This reverts commit e359084fda52dadf6851fda1f5a0d9305543277a. --- README.md | 6 ++++++ qmetaobject/Cargo.toml | 3 ++- qmetaobject/build.rs | 9 ++++----- qmetaobject/src/qtdeclarative.rs | 13 ++++++++++--- qttypes/Cargo.toml | 6 ++++-- qttypes/build.rs | 7 ++----- qttypes/src/lib.rs | 1 + 7 files changed, 29 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 058ee542..39ab46c9 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,12 @@ Enables `QtWebEngine` functionality. For more details see the [example](./exampl This feature is disabled by default. +### `widgets` + +Link against **`qtwidgets`** module. This will use `QApplication` instead of `QGuiApplication`. + +This feature is enabled by default. + ## What if a wrapper for the Qt C++ API is missing? It is quite likely that you would like to call a particular Qt function which diff --git a/qmetaobject/Cargo.toml b/qmetaobject/Cargo.toml index 02d6314b..9e38e913 100644 --- a/qmetaobject/Cargo.toml +++ b/qmetaobject/Cargo.toml @@ -12,9 +12,10 @@ keywords = ["Qt", "QML", "QMetaObject",] repository = "https://github.com/woboq/qmetaobject-rs" [features] -default = ["log"] +default = ["log", "widgets"] chrono_qdatetime = ["qttypes/chrono"] webengine = ["qttypes/qtwebengine"] +widgets = ["qttypes/qtwidgets"] [dependencies] qttypes = { path = "../qttypes", version = "0.2.5", features = ["qtquick"] } diff --git a/qmetaobject/build.rs b/qmetaobject/build.rs index c0d3ddd1..41e6147f 100644 --- a/qmetaobject/build.rs +++ b/qmetaobject/build.rs @@ -33,12 +33,11 @@ fn main() { config.flag("-F"); config.flag(&qt_library_path); } + if cfg!(not(feature = "widgets")) { + config.define("NO_WIDGETS", None); + } if qt_version >= Version::new(6, 0, 0) { - if std::env::var("CARGO_CFG_TARGET_OS").unwrap() == "android" { - config.flag("-std=c++17"); - } else { - config.flag_if_supported("-std=c++17"); - } + config.flag_if_supported("-std=c++17"); config.flag_if_supported("/std:c++17"); config.flag_if_supported("/Zc:__cplusplus"); } diff --git a/qmetaobject/src/qtdeclarative.rs b/qmetaobject/src/qtdeclarative.rs index 397bfa64..75d13fd0 100644 --- a/qmetaobject/src/qtdeclarative.rs +++ b/qmetaobject/src/qtdeclarative.rs @@ -28,8 +28,15 @@ cpp! {{ #include #include #include - #include #include + + #ifdef NO_WIDGETS + # define QAPPLICATION QGuiApplication + # include + #else + # define QAPPLICATION QApplication + # include + #endif struct SingleApplicationGuard { SingleApplicationGuard() { @@ -47,12 +54,12 @@ cpp! {{ }; struct QmlEngineHolder : SingleApplicationGuard { - std::unique_ptr app; + std::unique_ptr app; std::unique_ptr engine; std::unique_ptr view; QmlEngineHolder(int &argc, char **argv) - : app(new QApplication(argc, argv)) + : app(new QAPPLICATION(argc, argv)) , engine(new QQmlApplicationEngine()) {} }; diff --git a/qttypes/Cargo.toml b/qttypes/Cargo.toml index e5ca4764..49ce1976 100644 --- a/qttypes/Cargo.toml +++ b/qttypes/Cargo.toml @@ -27,13 +27,15 @@ qtquickcontrols2 = [] # Link against QtMultimedia qtmultimedia = [] # Link against QtMultimediaWidgets -qtmultimediawidgets = [] +qtmultimediawidgets = ["qtwidgets"] # Link against QtSql qtsql = [] # Link against QtTest qttest = [] +# Link against QtWidgets +qtwidgets = [] -default = ["required"] +default = ["required", "qtwidgets"] [dependencies] cpp = "0.5.6" diff --git a/qttypes/build.rs b/qttypes/build.rs index 203e71e8..fdf3d01a 100644 --- a/qttypes/build.rs +++ b/qttypes/build.rs @@ -167,11 +167,7 @@ fn main() { detect_qreal_size(&qt_include_path, &qt_library_path); if qt_version >= Version::new(6, 0, 0) { - if std::env::var("CARGO_CFG_TARGET_OS").unwrap() == "android" { - config.flag("-std=c++17"); - } else { - config.flag_if_supported("-std=c++17"); - } + config.flag_if_supported("-std=c++17"); config.flag_if_supported("/std:c++17"); config.flag_if_supported("/Zc:__cplusplus"); } @@ -213,6 +209,7 @@ fn main() { }; link_lib("Core"); link_lib("Gui"); + #[cfg(feature = "qtwidgets")] link_lib("Widgets"); #[cfg(feature = "qtquick")] link_lib("Quick"); diff --git a/qttypes/src/lib.rs b/qttypes/src/lib.rs index a42ad95c..71e034a1 100644 --- a/qttypes/src/lib.rs +++ b/qttypes/src/lib.rs @@ -116,6 +116,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //! | **`qtsql`** | Qt SQL | //! | **`qttest`** | Qt Test | //! | **`qtwebengine`** | Qt WebEngine | +//! | **`qtwidgets`** | Qt Widgets | //! #![cfg_attr(no_qt, allow(unused))] From 12dcb1653f620ec79b945a4847238a3b5437cf64 Mon Sep 17 00:00:00 2001 From: AdrianEddy Date: Fri, 5 May 2023 16:51:42 +0200 Subject: [PATCH 13/14] Fix call to `QMetaObject::invokeMethod` in Qt 6.5 --- qmetaobject/src/qtdeclarative.rs | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/qmetaobject/src/qtdeclarative.rs b/qmetaobject/src/qtdeclarative.rs index 25a75181..94efa98b 100644 --- a/qmetaobject/src/qtdeclarative.rs +++ b/qmetaobject/src/qtdeclarative.rs @@ -29,7 +29,7 @@ cpp! {{ #include #include #include - + #ifdef NO_WIDGETS # define QAPPLICATION QGuiApplication # include @@ -206,6 +206,8 @@ impl QmlEngine { let args_size = args.len(); let args_ptr = args.as_ptr(); + assert!(args_size <= 9); + cpp!(unsafe [ self as "QmlEngineHolder *", name as "QByteArray", @@ -219,23 +221,23 @@ impl QmlEngine { } QVariant ret; #if QT_VERSION >= QT_VERSION_CHECK(6,5,0) - QMetaMethodArgument args[9] = {}; + #define INVOKE_METHOD(...) QMetaObject::invokeMethod(robjs.first(), name, qReturnArg(ret), __VA_ARGS__); #else - QGenericArgument args[9] = {}; + #define INVOKE_METHOD(...) QMetaObject::invokeMethod(robjs.first(), name, Q_RETURN_ARG(QVariant, ret), __VA_ARGS__); #endif - for (uint i = 0; i < args_size; ++i) { - args[i] = Q_ARG(QVariant, args_ptr[i]); + 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; } - QMetaObject::invokeMethod( - robjs.first(), - name, - #if QT_VERSION >= QT_VERSION_CHECK(6,5,0) - qReturnArg(ret), - #else - Q_RETURN_ARG(QVariant, ret), - #endif - args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8] - ); + #undef INVOKE_METHOD return ret; }) } From 0a2fdfa950701147232529df7a39e81e644681cc Mon Sep 17 00:00:00 2001 From: AdrianEddy Date: Fri, 5 May 2023 17:18:10 +0200 Subject: [PATCH 14/14] Revert "Fix call to `QMetaObject::invokeMethod` in Qt 6.5" This reverts commit 12dcb1653f620ec79b945a4847238a3b5437cf64. --- qmetaobject/src/qtdeclarative.rs | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/qmetaobject/src/qtdeclarative.rs b/qmetaobject/src/qtdeclarative.rs index 94efa98b..25a75181 100644 --- a/qmetaobject/src/qtdeclarative.rs +++ b/qmetaobject/src/qtdeclarative.rs @@ -29,7 +29,7 @@ cpp! {{ #include #include #include - + #ifdef NO_WIDGETS # define QAPPLICATION QGuiApplication # include @@ -206,8 +206,6 @@ impl QmlEngine { let args_size = args.len(); let args_ptr = args.as_ptr(); - assert!(args_size <= 9); - cpp!(unsafe [ self as "QmlEngineHolder *", name as "QByteArray", @@ -221,23 +219,23 @@ impl QmlEngine { } QVariant ret; #if QT_VERSION >= QT_VERSION_CHECK(6,5,0) - #define INVOKE_METHOD(...) QMetaObject::invokeMethod(robjs.first(), name, qReturnArg(ret), __VA_ARGS__); + QMetaMethodArgument args[9] = {}; #else - #define INVOKE_METHOD(...) QMetaObject::invokeMethod(robjs.first(), name, Q_RETURN_ARG(QVariant, ret), __VA_ARGS__); + QGenericArgument args[9] = {}; #endif - 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; + for (uint i = 0; i < args_size; ++i) { + args[i] = Q_ARG(QVariant, args_ptr[i]); } - #undef INVOKE_METHOD + QMetaObject::invokeMethod( + robjs.first(), + name, + #if QT_VERSION >= QT_VERSION_CHECK(6,5,0) + qReturnArg(ret), + #else + Q_RETURN_ARG(QVariant, ret), + #endif + args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8] + ); return ret; }) }