diff --git a/CHANGELOG.md b/CHANGELOG.md index f1ea33422..0fa36cb8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ### Fixed - Memory leak in C++ + - Properly change all the colors when switching dark mode on or of (#687) ## [0.1.5] - 2021-11-24 diff --git a/api/sixtyfps-cpp/cbindgen.rs b/api/sixtyfps-cpp/cbindgen.rs index 597176889..21a73d348 100644 --- a/api/sixtyfps-cpp/cbindgen.rs +++ b/api/sixtyfps-cpp/cbindgen.rs @@ -382,10 +382,10 @@ fn gen_backend_qt(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> { config.export.include = items.iter().map(|x| x.to_string()).collect(); - config - .export - .body - .insert("NativeStyleMetrics".to_owned(), " inline NativeStyleMetrics();".to_owned()); + config.export.body.insert( + "NativeStyleMetrics".to_owned(), + " inline NativeStyleMetrics(); inline ~NativeStyleMetrics();".to_owned(), + ); let mut crate_dir = root_dir.to_owned(); crate_dir.extend(["sixtyfps_runtime", "rendering_backends", "qt"].iter()); diff --git a/api/sixtyfps-cpp/include/sixtyfps.h b/api/sixtyfps-cpp/include/sixtyfps.h index ce471c39e..21016485c 100644 --- a/api/sixtyfps-cpp/include/sixtyfps.h +++ b/api/sixtyfps-cpp/include/sixtyfps.h @@ -732,7 +732,12 @@ cbindgen_private::Flickable::~Flickable() cbindgen_private::NativeStyleMetrics::NativeStyleMetrics() { - sixtyfps_init_native_style_metrics(this); + sixtyfps_native_style_metrics_init(this); +} + +cbindgen_private::NativeStyleMetrics::~NativeStyleMetrics() +{ + sixtyfps_native_style_metrics_deinit(this); } #endif // !defined(DOXYGEN) diff --git a/sixtyfps_runtime/corelib/rtti.rs b/sixtyfps_runtime/corelib/rtti.rs index a95c7277b..12a05fd14 100644 --- a/sixtyfps_runtime/corelib/rtti.rs +++ b/sixtyfps_runtime/corelib/rtti.rs @@ -14,6 +14,7 @@ LICENSE END */ pub type FieldOffset = const_field_offset::FieldOffset; use crate::items::PropertyAnimation; +use alloc::rc::Rc; use core::convert::{TryFrom, TryInto}; use core::pin::Pin; @@ -332,3 +333,8 @@ pub trait BuiltinItem: Sized { fn fields() -> Vec<(&'static str, &'static dyn FieldInfo)>; fn callbacks() -> Vec<(&'static str, &'static dyn CallbackInfo)>; } + +/// Trait implemented by builtin globals +pub trait BuiltinGlobal: BuiltinItem { + fn new() -> Pin>; +} diff --git a/sixtyfps_runtime/interpreter/global_component.rs b/sixtyfps_runtime/interpreter/global_component.rs index 4092a1978..adaaec107 100644 --- a/sixtyfps_runtime/interpreter/global_component.rs +++ b/sixtyfps_runtime/interpreter/global_component.rs @@ -105,10 +105,10 @@ pub fn instantiate(description: &CompiledGlobal) -> (String, Pin Helper for (T, Next) { + impl Helper for (T, Next) { fn instantiate(name: &str) -> Pin> { if name == T::name() { - Rc::pin(T::default()) + T::new() } else { Next::instantiate(name) } diff --git a/sixtyfps_runtime/rendering_backends/qt/build.rs b/sixtyfps_runtime/rendering_backends/qt/build.rs index 71e88a938..40b286bf3 100644 --- a/sixtyfps_runtime/rendering_backends/qt/build.rs +++ b/sixtyfps_runtime/rendering_backends/qt/build.rs @@ -61,6 +61,7 @@ fn main() { println!("cargo:rerun-if-changed=qt_widgets/scrollview.rs"); println!("cargo:rerun-if-changed=qt_widgets/slider.rs"); println!("cargo:rerun-if-changed=qt_widgets/spinbox.rs"); + println!("cargo:rerun-if-changed=qt_widgets/stylemetrics.rs"); println!("cargo:rerun-if-changed=qt_widgets/tabwidget.rs"); println!("cargo:rerun-if-changed=lib.rs"); println!("cargo:SUPPORTS_NATIVE_STYLE=1"); diff --git a/sixtyfps_runtime/rendering_backends/qt/qt_widgets.rs b/sixtyfps_runtime/rendering_backends/qt/qt_widgets.rs index 296ee5e1a..9f61acdbb 100644 --- a/sixtyfps_runtime/rendering_backends/qt/qt_widgets.rs +++ b/sixtyfps_runtime/rendering_backends/qt/qt_widgets.rs @@ -201,100 +201,5 @@ pub use combobox::*; mod tabwidget; pub use tabwidget::*; -#[repr(C)] -#[derive(FieldOffsets, SixtyFPSElement)] -#[pin] -pub struct NativeStyleMetrics { - pub layout_spacing: Property, - pub layout_padding: Property, - pub text_cursor_width: Property, - pub window_background: Property, - pub default_text_color: Property, - pub textedit_background: Property, - pub textedit_text_color: Property, - pub textedit_background_disabled: Property, - pub textedit_text_color_disabled: Property, - - pub placeholder_color: Property, - pub placeholder_color_disabled: Property, -} - -impl Default for NativeStyleMetrics { - fn default() -> Self { - let s = NativeStyleMetrics { - layout_spacing: Default::default(), - layout_padding: Default::default(), - text_cursor_width: Default::default(), - window_background: Default::default(), - default_text_color: Default::default(), - textedit_background: Default::default(), - textedit_text_color: Default::default(), - textedit_background_disabled: Default::default(), - textedit_text_color_disabled: Default::default(), - placeholder_color: Default::default(), - placeholder_color_disabled: Default::default(), - }; - sixtyfps_init_native_style_metrics(&s); - s - } -} - -impl NativeStyleMetrics { - pub fn new() -> Pin> { - Rc::pin(Self::default()) - } -} - -/// Initialize the native style metrics -#[no_mangle] -pub extern "C" fn sixtyfps_init_native_style_metrics(self_: &NativeStyleMetrics) { - let layout_spacing = cpp!(unsafe [] -> f32 as "float" { - ensure_initialized(); - int spacing = qApp->style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing); - if (spacing < 0) - spacing = qApp->style()->layoutSpacing(QSizePolicy::DefaultType, QSizePolicy::DefaultType, Qt::Horizontal); - return spacing; - }); - self_.layout_spacing.set(layout_spacing.max(0.0)); - let layout_padding = cpp!(unsafe [] -> f32 as "float" { - ensure_initialized(); - return qApp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin); - }); - self_.layout_padding.set(layout_padding.max(0.0)); - let text_cursor_width = cpp!(unsafe [] -> f32 as "float" { - return qApp->style()->pixelMetric(QStyle::PM_TextCursorWidth); - }); - self_.text_cursor_width.set(text_cursor_width.max(0.0)); - let window_background = cpp!(unsafe[] -> u32 as "QRgb" { - return qApp->palette().color(QPalette::Window).rgba(); - }); - self_.window_background.set(Color::from_argb_encoded(window_background)); - let default_text_color = cpp!(unsafe[] -> u32 as "QRgb" { - return qApp->palette().color(QPalette::WindowText).rgba(); - }); - self_.default_text_color.set(Color::from_argb_encoded(default_text_color)); - let textedit_text_color = cpp!(unsafe[] -> u32 as "QRgb" { - return qApp->palette().color(QPalette::Text).rgba(); - }); - self_.textedit_text_color.set(Color::from_argb_encoded(textedit_text_color)); - let textedit_text_color_disabled = cpp!(unsafe[] -> u32 as "QRgb" { - return qApp->palette().color(QPalette::Disabled, QPalette::Text).rgba(); - }); - self_.textedit_text_color_disabled.set(Color::from_argb_encoded(textedit_text_color_disabled)); - let textedit_background = cpp!(unsafe[] -> u32 as "QRgb" { - return qApp->palette().color(QPalette::Base).rgba(); - }); - self_.textedit_background.set(Color::from_argb_encoded(textedit_background)); - let textedit_background_disabled = cpp!(unsafe[] -> u32 as "QRgb" { - return qApp->palette().color(QPalette::Disabled, QPalette::Base).rgba(); - }); - self_.textedit_background_disabled.set(Color::from_argb_encoded(textedit_background_disabled)); - let placeholder_color = cpp!(unsafe[] -> u32 as "QRgb" { - return qApp->palette().color(QPalette::PlaceholderText).rgba(); - }); - self_.placeholder_color.set(Color::from_argb_encoded(placeholder_color)); - let placeholder_color_disabled = cpp!(unsafe[] -> u32 as "QRgb" { - return qApp->palette().color(QPalette::Disabled, QPalette::PlaceholderText).rgba(); - }); - self_.placeholder_color_disabled.set(Color::from_argb_encoded(placeholder_color_disabled)); -} +mod stylemetrics; +pub use stylemetrics::*; diff --git a/sixtyfps_runtime/rendering_backends/qt/qt_widgets/stylemetrics.rs b/sixtyfps_runtime/rendering_backends/qt/qt_widgets/stylemetrics.rs new file mode 100644 index 000000000..8fa1d8b96 --- /dev/null +++ b/sixtyfps_runtime/rendering_backends/qt/qt_widgets/stylemetrics.rs @@ -0,0 +1,158 @@ +/* LICENSE BEGIN + This file is part of the SixtyFPS Project -- https://sixtyfps.io + Copyright (c) 2021 Olivier Goffart + Copyright (c) 2021 Simon Hausmann + + SPDX-License-Identifier: GPL-3.0-only + This file is also available under commercial licensing terms. + Please contact info@sixtyfps.io for more information. +LICENSE END */ + +use super::*; + +cpp! {{ +namespace { +struct StyleChangeListener : QWidget { + const void *nativeStyleMetrics = nullptr; + StyleChangeListener(const void *nativeStyleMetrics) : nativeStyleMetrics(nativeStyleMetrics) {} + bool event(QEvent *event) override { + auto ty = event->type(); + if (ty == QEvent::StyleChange || ty == QEvent::PaletteChange || ty == QEvent::FontChange) { + rust!(SFPS_style_change_event [nativeStyleMetrics: Pin<&NativeStyleMetrics> as "const void*"] { + nativeStyleMetrics.init(); + }); + } + return QWidget::event(event); + } +}; +} +}} + +#[repr(C)] +#[derive(FieldOffsets, SixtyFPSElement)] +#[pin] +#[pin_drop] +pub struct NativeStyleMetrics { + pub layout_spacing: Property, + pub layout_padding: Property, + pub text_cursor_width: Property, + pub window_background: Property, + pub default_text_color: Property, + pub textedit_background: Property, + pub textedit_text_color: Property, + pub textedit_background_disabled: Property, + pub textedit_text_color_disabled: Property, + + pub placeholder_color: Property, + pub placeholder_color_disabled: Property, + + pub style_change_listener: core::cell::Cell<*const u8>, +} + +impl const_field_offset::PinnedDrop for NativeStyleMetrics { + fn drop(self: Pin<&mut Self>) { + sixtyfps_native_style_metrics_deinit(self); + } +} + +impl NativeStyleMetrics { + pub fn new() -> Pin> { + let new = Rc::pin(NativeStyleMetrics { + layout_spacing: Default::default(), + layout_padding: Default::default(), + text_cursor_width: Default::default(), + window_background: Default::default(), + default_text_color: Default::default(), + textedit_background: Default::default(), + textedit_text_color: Default::default(), + textedit_background_disabled: Default::default(), + textedit_text_color_disabled: Default::default(), + placeholder_color: Default::default(), + placeholder_color_disabled: Default::default(), + style_change_listener: core::cell::Cell::new(core::ptr::null()), + }); + new.as_ref().init(); + new + } + + fn init(self: Pin<&Self>) { + if self.style_change_listener.get().is_null() { + self.style_change_listener.set(cpp!(unsafe [self as "void*"] -> *const u8 as "void*"{ + ensure_initialized(); + return new StyleChangeListener(self); + })); + } + + let layout_spacing = cpp!(unsafe [] -> f32 as "float" { + ensure_initialized(); + int spacing = qApp->style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing); + if (spacing < 0) + spacing = qApp->style()->layoutSpacing(QSizePolicy::DefaultType, QSizePolicy::DefaultType, Qt::Horizontal); + return spacing; + }); + self.layout_spacing.set(layout_spacing.max(0.0)); + let layout_padding = cpp!(unsafe [] -> f32 as "float" { + ensure_initialized(); + return qApp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin); + }); + self.layout_padding.set(layout_padding.max(0.0)); + let text_cursor_width = cpp!(unsafe [] -> f32 as "float" { + return qApp->style()->pixelMetric(QStyle::PM_TextCursorWidth); + }); + self.text_cursor_width.set(text_cursor_width.max(0.0)); + let window_background = cpp!(unsafe[] -> u32 as "QRgb" { + return qApp->palette().color(QPalette::Window).rgba(); + }); + self.window_background.set(Color::from_argb_encoded(window_background)); + let default_text_color = cpp!(unsafe[] -> u32 as "QRgb" { + return qApp->palette().color(QPalette::WindowText).rgba(); + }); + self.default_text_color.set(Color::from_argb_encoded(default_text_color)); + let textedit_text_color = cpp!(unsafe[] -> u32 as "QRgb" { + return qApp->palette().color(QPalette::Text).rgba(); + }); + self.textedit_text_color.set(Color::from_argb_encoded(textedit_text_color)); + let textedit_text_color_disabled = cpp!(unsafe[] -> u32 as "QRgb" { + return qApp->palette().color(QPalette::Disabled, QPalette::Text).rgba(); + }); + self.textedit_text_color_disabled + .set(Color::from_argb_encoded(textedit_text_color_disabled)); + let textedit_background = cpp!(unsafe[] -> u32 as "QRgb" { + return qApp->palette().color(QPalette::Base).rgba(); + }); + self.textedit_background.set(Color::from_argb_encoded(textedit_background)); + let textedit_background_disabled = cpp!(unsafe[] -> u32 as "QRgb" { + return qApp->palette().color(QPalette::Disabled, QPalette::Base).rgba(); + }); + self.textedit_background_disabled + .set(Color::from_argb_encoded(textedit_background_disabled)); + let placeholder_color = cpp!(unsafe[] -> u32 as "QRgb" { + return qApp->palette().color(QPalette::PlaceholderText).rgba(); + }); + self.placeholder_color.set(Color::from_argb_encoded(placeholder_color)); + let placeholder_color_disabled = cpp!(unsafe[] -> u32 as "QRgb" { + return qApp->palette().color(QPalette::Disabled, QPalette::PlaceholderText).rgba(); + }); + self.placeholder_color_disabled.set(Color::from_argb_encoded(placeholder_color_disabled)); + } +} + +#[cfg(feature = "rtti")] +impl sixtyfps_corelib::rtti::BuiltinGlobal for NativeStyleMetrics { + fn new() -> Pin> { + NativeStyleMetrics::new() + } +} + +#[no_mangle] +pub extern "C" fn sixtyfps_native_style_metrics_init(self_: Pin<&NativeStyleMetrics>) { + self_.style_change_listener.set(core::ptr::null()); // because the C++ code don't initialize it + self_.init(); +} + +#[no_mangle] +pub extern "C" fn sixtyfps_native_style_metrics_deinit(self_: Pin<&mut NativeStyleMetrics>) { + let scl = self_.style_change_listener.get(); + cpp!(unsafe [scl as "StyleChangeListener*"] { delete scl; }); + self_.style_change_listener.set(core::ptr::null()); +}