slint/internal/backends/qt/lib.rs
Olivier Goffart 2e5ab86bea Rename backend module to platform
and the Backend trait into PlatfromAbstraction trait
2022-08-23 19:39:49 +02:00

252 lines
7.6 KiB
Rust

// Copyright © SixtyFPS GmbH <info@slint-ui.com>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
// cSpell: ignore deinit fnbox qsize
#![doc = include_str!("README.md")]
#![doc(html_logo_url = "https://slint-ui.com/logo/slint-logo-square-light.svg")]
#![recursion_limit = "2048"]
extern crate alloc;
#[cfg(not(no_qt))]
mod qt_accessible;
#[cfg(not(no_qt))]
mod qt_widgets;
#[cfg(not(no_qt))]
mod qt_window;
mod accessible_generated;
mod key_generated;
#[doc(hidden)]
#[cold]
#[cfg(not(target_arch = "wasm32"))]
pub fn use_modules() -> usize {
#[cfg(no_qt)]
{
ffi::slint_qt_get_widget as usize
}
#[cfg(not(no_qt))]
{
qt_window::ffi::slint_qt_get_widget as usize
+ (&qt_widgets::NativeButtonVTable) as *const _ as usize
}
}
#[cfg(no_qt)]
mod ffi {
#[no_mangle]
pub extern "C" fn slint_qt_get_widget(
_: &i_slint_core::window::PlatformWindowRc,
) -> *mut std::ffi::c_void {
std::ptr::null_mut()
}
}
/// NativeWidgets and NativeGlobals are "type list" containing all the native widgets and global types.
///
/// It is built as a tuple `(Type, Tail)` where `Tail` is also a "type list". a `()` is the end.
///
/// So it can be used like this to do something for all types:
///
/// ```rust
/// trait DoSomething {
/// fn do_something(/*...*/) { /*...*/
/// }
/// }
/// impl DoSomething for () {}
/// impl<T: i_slint_core::rtti::BuiltinItem, Next: DoSomething> DoSomething for (T, Next) {
/// fn do_something(/*...*/) {
/// /*...*/
/// Next::do_something(/*...*/);
/// }
/// }
/// i_slint_backend_qt::NativeWidgets::do_something(/*...*/)
/// ```
#[cfg(not(no_qt))]
#[rustfmt::skip]
pub type NativeWidgets =
(qt_widgets::NativeButton,
(qt_widgets::NativeCheckBox,
(qt_widgets::NativeSlider,
(qt_widgets::NativeSpinBox,
(qt_widgets::NativeGroupBox,
(qt_widgets::NativeLineEdit,
(qt_widgets::NativeScrollView,
(qt_widgets::NativeStandardListViewItem,
(qt_widgets::NativeComboBox,
(qt_widgets::NativeComboBoxPopup,
(qt_widgets::NativeTabWidget,
(qt_widgets::NativeTab,
()))))))))))));
#[cfg(not(no_qt))]
#[rustfmt::skip]
pub type NativeGlobals =
(qt_widgets::NativeStyleMetrics,
());
#[cfg(no_qt)]
mod native_style_metrics_stub {
use const_field_offset::FieldOffsets;
use core::pin::Pin;
#[cfg(feature = "rtti")]
use i_slint_core::rtti::*;
use i_slint_core_macros::*;
/// cbindgen:ignore
#[repr(C)]
#[derive(FieldOffsets, SlintElement)]
#[pin]
#[pin_drop]
pub struct NativeStyleMetrics {}
impl const_field_offset::PinnedDrop for NativeStyleMetrics {
fn drop(self: Pin<&mut Self>) {}
}
}
pub mod native_widgets {
#[cfg(not(no_qt))]
pub use super::qt_widgets::*;
#[cfg(no_qt)]
pub use super::native_style_metrics_stub::NativeStyleMetrics;
}
#[cfg(no_qt)]
pub type NativeWidgets = ();
#[cfg(no_qt)]
pub type NativeGlobals = ();
pub const HAS_NATIVE_STYLE: bool = cfg!(not(no_qt));
use std::rc::Rc;
#[cfg(not(no_qt))]
pub use qt_widgets::{native_style_metrics_deinit, native_style_metrics_init};
#[cfg(no_qt)]
pub fn native_style_metrics_init(_: core::pin::Pin<&native_widgets::NativeStyleMetrics>) {
panic!("Qt backend not present");
}
#[cfg(no_qt)]
pub fn native_style_metrics_deinit(_: core::pin::Pin<&mut native_widgets::NativeStyleMetrics>) {
panic!("Qt backend not present");
}
pub struct Backend;
impl i_slint_core::platform::PlatformAbstraction for Backend {
fn create_window(&self) -> Rc<dyn i_slint_core::window::PlatformWindow> {
#[cfg(no_qt)]
panic!("The Qt backend needs Qt");
#[cfg(not(no_qt))]
{
qt_window::QtWindow::new()
}
}
fn run_event_loop(&self, _behavior: i_slint_core::platform::EventLoopQuitBehavior) {
#[cfg(not(no_qt))]
{
let quit_on_last_window_closed = match _behavior {
i_slint_core::platform::EventLoopQuitBehavior::QuitOnLastWindowClosed => true,
i_slint_core::platform::EventLoopQuitBehavior::QuitOnlyExplicitly => false,
};
// Schedule any timers with Qt that were set up before this event loop start.
crate::qt_window::timer_event();
use cpp::cpp;
cpp! {unsafe [quit_on_last_window_closed as "bool"] {
ensure_initialized(true);
qApp->setQuitOnLastWindowClosed(quit_on_last_window_closed);
qApp->exec();
} }
};
}
fn quit_event_loop(&self) {
#[cfg(not(no_qt))]
{
use cpp::cpp;
cpp! {unsafe [] {
// Use a quit event to avoid qApp->quit() calling
// [NSApp terminate:nil] and us never returning from the
// event loop - slint-viewer relies on the ability to
// return from run().
QCoreApplication::postEvent(qApp, new QEvent(QEvent::Quit));
} }
};
}
fn post_event(&self, _event: Box<dyn FnOnce() + Send>) {
#[cfg(not(no_qt))]
{
use cpp::cpp;
cpp! {{
struct TraitObject { void *a, *b; };
struct EventHolder {
TraitObject fnbox = {nullptr, nullptr};
~EventHolder() {
if (fnbox.a != nullptr || fnbox.b != nullptr) {
rust!(Slint_delete_event_holder [fnbox: *mut dyn FnOnce() as "TraitObject"] {
drop(Box::from_raw(fnbox))
});
}
}
EventHolder(TraitObject f) : fnbox(f) {}
EventHolder(const EventHolder&) = delete;
EventHolder& operator=(const EventHolder&) = delete;
EventHolder(EventHolder&& other) : fnbox(other.fnbox) {
other.fnbox = {nullptr, nullptr};
}
void operator()() {
if (fnbox.a != nullptr || fnbox.b != nullptr) {
TraitObject fnbox = std::move(this->fnbox);
this->fnbox = {nullptr, nullptr};
rust!(Slint_call_event_holder [fnbox: *mut dyn FnOnce() as "TraitObject"] {
let b = Box::from_raw(fnbox);
b();
});
}
}
};
}};
let fnbox = Box::into_raw(_event);
cpp! {unsafe [fnbox as "TraitObject"] {
QTimer::singleShot(0, qApp, EventHolder{fnbox});
}}
};
}
fn set_clipboard_text(&self, _text: &str) {
#[cfg(not(no_qt))]
{
use cpp::cpp;
let text: qttypes::QString = _text.into();
cpp! {unsafe [text as "QString"] {
ensure_initialized();
QGuiApplication::clipboard()->setText(text);
} }
}
}
fn clipboard_text(&self) -> Option<String> {
#[cfg(not(no_qt))]
{
use cpp::cpp;
let has_text = cpp! {unsafe [] -> bool as "bool" {
ensure_initialized();
return QGuiApplication::clipboard()->mimeData()->hasText();
} };
if has_text {
return Some(
cpp! { unsafe [] -> qttypes::QString as "QString" {
return QGuiApplication::clipboard()->text();
}}
.into(),
);
}
}
None
}
}