diff --git a/api/cpp/lib.rs b/api/cpp/lib.rs index 93a3a49aed0..70bf54e50af 100644 --- a/api/cpp/lib.rs +++ b/api/cpp/lib.rs @@ -230,3 +230,8 @@ pub unsafe extern "C" fn slint_set_xdg_app_id(_app_id: &SharedString) { pub unsafe extern "C" fn slint_detect_operating_system() -> OperatingSystemType { i_slint_core::detect_operating_system() } + +#[unsafe(no_mangle)] +pub extern "C" fn open_url(url: &SharedString) { + i_slint_core::open_url(url) +} diff --git a/internal/compiler/expression_tree.rs b/internal/compiler/expression_tree.rs index ac37ccd9981..05f2b3eae61 100644 --- a/internal/compiler/expression_tree.rs +++ b/internal/compiler/expression_tree.rs @@ -111,6 +111,7 @@ pub enum BuiltinFunction { StartTimer, StopTimer, RestartTimer, + OpenUrl, } #[derive(Debug, Clone)] @@ -276,6 +277,7 @@ declare_builtin_function_types!( StartTimer: (Type::ElementReference) -> Type::Void, StopTimer: (Type::ElementReference) -> Type::Void, RestartTimer: (Type::ElementReference) -> Type::Void, + OpenUrl: (Type::String) -> Type::Void ); impl BuiltinFunction { @@ -369,6 +371,7 @@ impl BuiltinFunction { BuiltinFunction::StartTimer => false, BuiltinFunction::StopTimer => false, BuiltinFunction::RestartTimer => false, + BuiltinFunction::OpenUrl => false, } } @@ -446,6 +449,7 @@ impl BuiltinFunction { BuiltinFunction::StartTimer => false, BuiltinFunction::StopTimer => false, BuiltinFunction::RestartTimer => false, + BuiltinFunction::OpenUrl => false, } } } diff --git a/internal/compiler/generator/cpp.rs b/internal/compiler/generator/cpp.rs index 4875b76ef41..b04e3e1d01f 100644 --- a/internal/compiler/generator/cpp.rs +++ b/internal/compiler/generator/cpp.rs @@ -4201,6 +4201,10 @@ fn compile_builtin_function_call( panic!("internal error: invalid args to RetartTimer {arguments:?}") } } + BuiltinFunction::OpenUrl => { + let url = a.next().unwrap(); + format!("slint::cbindgen_private::open_url({})", url) + } } } diff --git a/internal/compiler/generator/rust.rs b/internal/compiler/generator/rust.rs index 90fac838edd..6d48a6e8653 100644 --- a/internal/compiler/generator/rust.rs +++ b/internal/compiler/generator/rust.rs @@ -3454,6 +3454,10 @@ fn compile_builtin_function_call( panic!("internal error: invalid args to RestartTimer {arguments:?}") } } + BuiltinFunction::OpenUrl => { + let url = a.next().unwrap(); + quote!(sp::open_url(&#url)) + } } } diff --git a/internal/compiler/llr/optim_passes/inline_expressions.rs b/internal/compiler/llr/optim_passes/inline_expressions.rs index e1062d16016..e08e2c0dde3 100644 --- a/internal/compiler/llr/optim_passes/inline_expressions.rs +++ b/internal/compiler/llr/optim_passes/inline_expressions.rs @@ -155,6 +155,7 @@ fn builtin_function_cost(function: &BuiltinFunction) -> isize { BuiltinFunction::StartTimer => 10, BuiltinFunction::StopTimer => 10, BuiltinFunction::RestartTimer => 10, + BuiltinFunction::OpenUrl => isize::MAX, } } diff --git a/internal/compiler/lookup.rs b/internal/compiler/lookup.rs index 9440e412a7a..68274f14470 100644 --- a/internal/compiler/lookup.rs +++ b/internal/compiler/lookup.rs @@ -809,6 +809,7 @@ impl LookupObject for SlintInternal { .or_else(|| f("date-now", b(BuiltinFunction::DateNow))) .or_else(|| f("valid-date", b(BuiltinFunction::ValidDate))) .or_else(|| f("parse-date", b(BuiltinFunction::ParseDate))) + .or_else(|| f("open-url", b(BuiltinFunction::OpenUrl))) } } diff --git a/internal/core/Cargo.toml b/internal/core/Cargo.toml index f52210daa0a..f6c41ffd210 100644 --- a/internal/core/Cargo.toml +++ b/internal/core/Cargo.toml @@ -41,6 +41,7 @@ std = [ "chrono/wasmbind", "chrono/clock", "dep:sys-locale", + "dep:webbrowser", ] # Unsafe feature meaning that there is only one core running and all thread_local are static. # You can only enable this feature if you are sure that any API of this crate is only called @@ -129,6 +130,8 @@ wgpu-27 = { workspace = true, optional = true } tr = { workspace = true, optional = true } +webbrowser = { version = "1.0.6", optional = true } + [target.'cfg(target_family = "unix")'.dependencies] gettext-rs = { version = "0.7.1", optional = true, features = ["gettext-system"] } diff --git a/internal/core/lib.rs b/internal/core/lib.rs index 3ce59b5cbab..e9275074f82 100644 --- a/internal/core/lib.rs +++ b/internal/core/lib.rs @@ -148,3 +148,11 @@ pub fn detect_operating_system() -> OperatingSystemType { pub fn is_apple_platform() -> bool { matches!(detect_operating_system(), OperatingSystemType::Macos | OperatingSystemType::Ios) } + +#[cfg_attr(not(feature = "std"), allow(unused))] +pub fn open_url(url: &str) { + #[cfg(feature = "std")] + if let Err(err) = webbrowser::open(url) { + debug_log!("Error opening url {}: {}", url, err); + } +} diff --git a/internal/interpreter/eval.rs b/internal/interpreter/eval.rs index f39766e6eed..f15ca9cbc54 100644 --- a/internal/interpreter/eval.rs +++ b/internal/interpreter/eval.rs @@ -1389,6 +1389,12 @@ fn call_builtin_function( panic!("internal error: argument to RestartTimer must be an element") } } + BuiltinFunction::OpenUrl => { + let url: SharedString = + eval_expression(&arguments[0], local_context).try_into().unwrap(); + corelib::open_url(&url); + Value::Void + } } }