#![doc(html_logo_url = "https://sciter.com/screenshots/slide-sciter-osx.png",
html_favicon_url = "https://sciter.com/wp-content/themes/sciter/!images/favicon.ico")]
#![allow(clippy::needless_return, clippy::let_and_return)] #![allow(clippy::redundant_field_names)] #![allow(clippy::unreadable_literal)] #![allow(clippy::upper_case_acronyms)]#![allow(clippy::deprecated_semver)] #![allow(clippy::result_unit_err)]
#[cfg(target_os = "macos")]
#[macro_use] extern crate objc;
#[macro_use] extern crate lazy_static;
#[macro_use] pub mod macros;
mod capi;
#[doc(hidden)]
pub use capi::scdom::{HELEMENT};
pub use capi::scdef::{GFX_LAYER, SCRIPT_RUNTIME_FEATURES};
mod platform;
mod eventhandler;
pub mod dom;
pub mod graphics;
pub mod host;
pub mod om;
pub mod request;
pub mod types;
pub mod utf;
pub mod value;
pub mod video;
pub mod window;
pub mod windowless;
pub use dom::Element;
pub use dom::event::EventHandler;
pub use host::{Archive, Host, HostHandler};
pub use value::{Value, FromValue};
pub use window::Window;
pub type WindowBuilder = window::Builder;
pub use capi::scapi::{ISciterAPI};
use capi::scgraphics::SciterGraphicsAPI;
use capi::screquest::SciterRequestAPI;
#[cfg(windows)]
mod ext {
#![allow(non_snake_case, non_camel_case_types)]
use capi::scapi::{ISciterAPI};
use capi::sctypes::{LPCSTR, LPCVOID, BOOL};
type ApiType = *const ISciterAPI;
type FuncType = extern "system" fn () -> *const ISciterAPI;
pub static mut CUSTOM_DLL_PATH: Option<String> = None;
extern "system"
{
fn LoadLibraryA(lpFileName: LPCSTR) -> LPCVOID;
fn FreeLibrary(dll: LPCVOID) -> BOOL;
fn GetProcAddress(hModule: LPCVOID, lpProcName: LPCSTR) -> LPCVOID;
}
pub fn try_load_library(permanent: bool) -> ::std::result::Result<ApiType, String> {
use std::ffi::CString;
use std::path::Path;
fn try_load(path: &Path) -> Option<LPCVOID> {
let path = CString::new(format!("{}", path.display())).expect("invalid library path");
let dll = unsafe { LoadLibraryA(path.as_ptr()) };
if !dll.is_null() {
Some(dll)
} else {
None
}
}
fn in_global() -> Option<LPCVOID> {
let mut dll = unsafe { LoadLibraryA(b"sciter.dll\0".as_ptr() as LPCSTR) };
if dll.is_null() {
let alternate = if cfg!(target_arch = "x86_64") { b"sciter64.dll\0" } else { b"sciter32.dll\0" };
dll = unsafe { LoadLibraryA(alternate.as_ptr() as LPCSTR) };
}
if !dll.is_null() {
Some(dll)
} else {
None
}
}
let dll = if let Some(path) = unsafe { CUSTOM_DLL_PATH.as_ref() } {
try_load(Path::new(path))
} else {
in_global()
};
if let Some(dll) = dll {
let sym = unsafe { GetProcAddress(dll, b"SciterAPI\0".as_ptr() as LPCSTR) };
if sym.is_null() {
return Err("\"SciterAPI\" function was expected in the loaded library.".to_owned());
}
if !permanent {
unsafe { FreeLibrary(dll) };
return Ok(0 as ApiType);
}
let get_api: FuncType = unsafe { std::mem::transmute(sym) };
return Ok(get_api());
}
let sdkbin = if cfg!(target_arch = "x86_64") { "bin/64" } else { "bin/32" };
let msg = format!("Please verify that Sciter SDK is installed and its binaries (from SDK/{}) are available in PATH.", sdkbin);
Err(format!("error: '{}' was not found neither in PATH nor near the current executable.\n {}", "sciter.dll", msg))
}
pub unsafe fn SciterAPI() -> *const ISciterAPI {
match try_load_library(true) {
Ok(api) => api,
Err(error) => panic!("{}", error),
}
}
}
#[cfg(all(feature = "dynamic", unix))]
mod ext {
#![allow(non_snake_case, non_camel_case_types)]
extern crate libc;
pub static mut CUSTOM_DLL_PATH: Option<String> = None;
#[cfg(target_os = "linux")]
const DLL_NAMES: &[&str] = &[ "libsciter-gtk.so" ];
#[cfg(target_os = "macos")]
const DLL_NAMES: &[&str] = &[ "libsciter.dylib", "sciter-osx-64.dylib" ];
use capi::scapi::ISciterAPI;
use capi::sctypes::{LPVOID, LPCSTR};
type FuncType = extern "system" fn () -> *const ISciterAPI;
type ApiType = *const ISciterAPI;
pub fn try_load_library(permanent: bool) -> ::std::result::Result<ApiType, String> {
use std::ffi::CString;
use std::os::unix::ffi::OsStrExt;
use std::path::{Path};
fn try_load(path: &Path) -> Option<LPVOID> {
let bytes = path.as_os_str().as_bytes();
if let Ok(cstr) = CString::new(bytes) {
let dll = unsafe { libc::dlopen(cstr.as_ptr(), libc::RTLD_LOCAL | libc::RTLD_LAZY) };
if !dll.is_null() {
return Some(dll)
}
}
None
}
fn try_load_from(dir: Option<&Path>) -> Option<LPVOID> {
let dll = DLL_NAMES.iter()
.map(|name| {
let mut path = dir.map(Path::to_owned).unwrap_or_default();
path.push(name);
path
})
.map(|path| try_load(&path))
.find(|dll| dll.is_some())
.map(|o| o.unwrap());
if dll.is_some() {
return dll;
}
None
}
fn in_current_dir() -> Option<LPVOID> {
if let Ok(dir) = ::std::env::current_exe() {
if let Some(dir) = dir.parent() {
let dll = try_load_from(Some(dir));
if dll.is_some() {
return dll;
}
if cfg!(target_os = "macos") {
let mut path = dir.to_owned();
path.push("../Frameworks/libsciter.dylib");
let dll = try_load(&path);
if dll.is_some() {
return dll;
}
let mut path = dir.to_owned();
path.push("../Frameworks/sciter-osx-64.dylib");
let dll = try_load(&path);
if dll.is_some() {
return dll;
}
}
}
}
None
}
fn in_global() -> Option<LPVOID> {
try_load_from(None)
}
fn in_paths() -> Option<LPVOID> {
use std::env;
if let Some(paths) = env::var_os("PATH") {
for path in env::split_paths(&paths) {
if let Some(dll) = try_load_from(Some(&path)) {
return Some(dll);
}
}
}
None
}
let dll = if let Some(path) = unsafe { CUSTOM_DLL_PATH.as_ref() } {
try_load(Path::new(path))
} else {
in_current_dir().or_else(in_paths).or_else(in_global)
};
if let Some(dll) = dll {
let sym = unsafe { libc::dlsym(dll, b"SciterAPI\0".as_ptr() as LPCSTR) };
if sym.is_null() {
return Err("\"SciterAPI\" function was expected in the loaded library.".to_owned());
}
if !permanent {
unsafe { libc::dlclose(dll) };
return Ok(0 as ApiType);
}
let get_api: FuncType = unsafe { std::mem::transmute(sym) };
return Ok(get_api());
}
let sdkbin = if cfg!(target_os = "macos") { "bin.osx" } else { "bin.lnx" };
let msg = format!("Please verify that Sciter SDK is installed and its binaries (from {}) are available in PATH.", sdkbin);
Err(format!("error: '{}' was not found neither in PATH nor near the current executable.\n {}", DLL_NAMES[0], msg))
}
pub fn SciterAPI() -> *const ISciterAPI {
match try_load_library(true) {
Ok(api) => api,
Err(error) => panic!("{}", error),
}
}
}
#[cfg(all(target_os = "linux", not(feature = "dynamic")))]
mod ext {
#[link(name = "sciter-gtk")]
extern "system" { pub fn SciterAPI() -> *const ::capi::scapi::ISciterAPI; }
}
#[cfg(all(target_os = "macos", target_arch = "x86_64", not(feature = "dynamic")))]
mod ext {
#[link(name = "libsciter", kind = "dylib")]
extern "system" { pub fn SciterAPI() -> *const ::capi::scapi::ISciterAPI; }
}
#[doc(hidden)]
#[allow(non_snake_case)]
pub fn SciterAPI<'a>() -> &'a ISciterAPI {
let ap = unsafe {
if cfg!(feature="extension") {
if cfg!(test) {
&*ext::SciterAPI()
} else {
EXT_API
.expect("Sciter API is not available yet, call `sciter::set_api()` first.")
}
} else {
&*ext::SciterAPI()
}
};
let abi_version = ap.version;
if cfg!(feature = "windowless") {
assert!(abi_version >= 0x0001_0001, "Incompatible Sciter build and \"windowless\" feature");
}
if cfg!(not(feature = "windowless")) {
assert!(abi_version < 0x0001_0000, "Incompatible Sciter build and \"windowless\" feature");
}
return ap;
}
#[doc(hidden)]
#[allow(non_snake_case)]
pub fn SciterAPI_unchecked<'a>() -> &'a ISciterAPI {
let ap = unsafe {
if cfg!(feature="extension") {
EXT_API.expect("Sciter API is not available yet, call `sciter::set_api()` first.")
} else {
&*ext::SciterAPI()
}
};
return ap;
}
lazy_static! {
static ref _API: &'static ISciterAPI = SciterAPI();
static ref _GAPI: &'static SciterGraphicsAPI = {
if version_num() < 0x0401_0A00 {
panic!("Graphics API is incompatible since 4.1.10 (your version is {})", version());
}
unsafe { &*(SciterAPI().GetSciterGraphicsAPI)() }
};
static ref _RAPI: &'static SciterRequestAPI = unsafe { &*(SciterAPI().GetSciterRequestAPI)() };
}
pub fn set_library(custom_path: &str) -> ::std::result::Result<(), String> {
#[cfg(not(feature = "dynamic"))]
fn set_impl(_: &str) -> ::std::result::Result<(), String> {
Err("Don't use `sciter::set_library()` in static builds.\n Build with the feature \"dynamic\" instead.".to_owned())
}
#[cfg(feature = "dynamic")]
fn set_impl(path: &str) -> ::std::result::Result<(), String> {
unsafe {
ext::CUSTOM_DLL_PATH = Some(path.to_owned());
}
ext::try_load_library(false).map(|_| ())
}
set_impl(custom_path)
}
static mut EXT_API: Option<&'static ISciterAPI> = None;
pub fn set_host_api(api: &'static ISciterAPI) {
if cfg!(feature="extension") {
unsafe {
EXT_API.replace(api);
}
}
}
pub fn version_num() -> u32 {
use types::BOOL;
let v1 = (_API.SciterVersion)(true as BOOL);
let v2 = (_API.SciterVersion)(false as BOOL);
let (major, minor, revision, _build) = (v1 >> 16 & 0xFF, v1 & 0xFF, v2 >> 16 & 0xFF, v2 & 0xFF);
let num = (major << 24) | (minor << 16) | (revision << 8);
return num;
}
pub fn version() -> String {
use types::BOOL;
let v1 = (_API.SciterVersion)(true as BOOL);
let v2 = (_API.SciterVersion)(false as BOOL);
let num = [v1 >> 16, v1 & 0xFFFF, v2 >> 16, v2 & 0xFFFF];
let version = format!("{}.{}.{}.{}", num[0], num[1], num[2], num[3]);
return version;
}
pub fn api_version() -> u32 {
_API.version
}
pub fn is_windowless() -> bool {
api_version() >= 0x0001_0001
}
#[derive(Copy, Clone)]
pub enum RuntimeOptions<'a> {
LibraryPath(&'a str),
GfxLayer(GFX_LAYER),
UxTheming(bool),
DebugMode(bool),
ScriptFeatures(u8),
ConnectionTimeout(u32),
OnHttpsError(u8),
InitScript(&'a str),
MaxHttpDataLength(usize),
LogicalPixel(bool),
}
pub fn set_options(options: RuntimeOptions) -> std::result::Result<(), ()> {
use RuntimeOptions::*;
use capi::scdef::SCITER_RT_OPTIONS::*;
let (option, value) = match options {
ConnectionTimeout(ms) => (SCITER_CONNECTION_TIMEOUT, ms as usize),
OnHttpsError(behavior) => (SCITER_HTTPS_ERROR, behavior as usize),
InitScript(script) => (SCITER_SET_INIT_SCRIPT, script.as_bytes().as_ptr() as usize),
ScriptFeatures(mask) => (SCITER_SET_SCRIPT_RUNTIME_FEATURES, mask as usize),
GfxLayer(backend) => (SCITER_SET_GFX_LAYER, backend as usize),
DebugMode(enable) => (SCITER_SET_DEBUG_MODE, enable as usize),
UxTheming(enable) => (SCITER_SET_UX_THEMING, enable as usize),
MaxHttpDataLength(value) => (SCITER_SET_MAX_HTTP_DATA_LENGTH, value),
LogicalPixel(enable) => (SCITER_SET_PX_AS_DIP, enable as usize),
LibraryPath(path) => {
return set_library(path).map_err(|_|());
}
};
let ok = (_API.SciterSetOption)(std::ptr::null_mut(), option, value);
if ok != 0 {
Ok(())
} else {
Err(())
}
}
pub fn set_variable(path: &str, value: Value) -> dom::Result<()> {
let ws = s2u!(path);
let ok = (_API.SciterSetVariable)(std::ptr::null_mut(), ws.as_ptr(), value.as_cptr());
if ok == dom::SCDOM_RESULT::OK {
Ok(())
} else {
Err(ok)
}
}
#[doc(hidden)]
pub fn get_variable(path: &str) -> dom::Result<Value> {
let ws = s2u!(path);
let mut value = Value::new();
let ok = (_API.SciterGetVariable)(std::ptr::null_mut(), ws.as_ptr(), value.as_mut_ptr());
if ok == dom::SCDOM_RESULT::OK {
Ok(value)
} else {
Err(ok)
}
}