├── src ├── capi │ ├── scarchive.rs │ ├── mod.rs │ ├── sctiscript.rs │ ├── schandler.rs │ ├── sctypes.rs │ ├── scvalue.rs │ ├── scom.rs │ ├── screquest.rs │ └── scdom.rs ├── types.rs ├── macros.rs ├── utf.rs ├── om.rs ├── request.rs ├── eventhandler.rs └── windowless.rs ├── .clippy.toml ├── .gitignore ├── examples ├── icon.png ├── archived.rc ├── extension.htm ├── archived.rs ├── extension │ ├── Cargo.toml │ └── src │ │ └── extension.rs ├── windowless │ ├── Cargo.toml │ └── src │ │ └── windowless.rs ├── threads.rs ├── fire_event.htm ├── first.rs ├── som.htm ├── fire_event.rs ├── minimal.rs ├── download.rs ├── interop.htm ├── threads.htm ├── video.htm ├── clock.htm ├── minimal.htm ├── interop.rs ├── video.rs ├── som.rs └── dom.rs ├── .rustfmt.toml ├── .editorconfig ├── .github └── workflows │ ├── clippy.yml │ ├── sciter-tis.yml │ └── sciter-js.yml ├── serde ├── Cargo.toml ├── src │ ├── error.rs │ ├── lib.rs │ ├── de.rs │ └── ser.rs └── tests │ ├── deserialization.rs │ ├── serialization.rs │ └── both.rs ├── LICENSE ├── .appveyor.yml ├── .travis.yml ├── Cargo.toml ├── tests └── graphics.rs └── README.md /src/capi/scarchive.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.clippy.toml: -------------------------------------------------------------------------------- 1 | doc-valid-idents = ["TIScript"] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | .vscode/ 4 | .vs/ 5 | -------------------------------------------------------------------------------- /examples/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/rust-sciter/HEAD/examples/icon.png -------------------------------------------------------------------------------- /examples/archived.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sciter-sdk/rust-sciter/HEAD/examples/archived.rc -------------------------------------------------------------------------------- /src/types.rs: -------------------------------------------------------------------------------- 1 | //! Export platform-dependent types used by Sciter. 2 | 3 | pub use capi::sctypes::*; 4 | pub use capi::scdef::*; 5 | pub use capi::scvalue::VALUE; 6 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | # `rustfmt --config-help` for formatting options 2 | max_width = 140 3 | ideal_width = 120 4 | tab_spaces = 2 5 | hard_tabs = true 6 | blank_lines_upper_bound = 2 7 | -------------------------------------------------------------------------------- /src/capi/mod.rs: -------------------------------------------------------------------------------- 1 | /*! C interface headers */ 2 | 3 | pub mod scapi; 4 | pub mod scbehavior; 5 | pub mod scdef; 6 | pub mod scdom; 7 | pub mod scgraphics; 8 | pub mod screquest; 9 | pub mod sctiscript; 10 | pub mod sctypes; 11 | pub mod scvalue; 12 | pub mod schandler; 13 | pub mod scmsg; 14 | pub mod scom; 15 | -------------------------------------------------------------------------------- /src/capi/sctiscript.rs: -------------------------------------------------------------------------------- 1 | //! TIScript Virtual Machine Runtime. 2 | 3 | #![allow(non_camel_case_types, non_snake_case)] 4 | 5 | use capi::sctypes::{LPVOID, UINT64}; 6 | 7 | MAKE_HANDLE!(#[doc = "TIScript VM native handle."] HVM, _HVM); 8 | 9 | pub type tiscript_value = UINT64; 10 | 11 | #[repr(C)] 12 | pub struct tiscript_native_interface 13 | { 14 | create_vm: LPVOID, 15 | } 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | 9 | [*.rs] 10 | indent_style = tab 11 | indent_size = 2 12 | tab_width = 2 13 | 14 | [*.{yml,toml,md}] 15 | indent_style = space 16 | indent_size = 2 17 | tab_width = 2 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /examples/extension.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | extension test 4 | 6 | 14 | 15 | 16 |

see logs in Inspector

17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/archived.rs: -------------------------------------------------------------------------------- 1 | //! Sciter sample with archived resources. 2 | 3 | extern crate sciter; 4 | 5 | fn main() { 6 | let resources = include_bytes!("archived.rc"); 7 | 8 | let mut frame = sciter::WindowBuilder::main_window() 9 | .fixed() 10 | .with_size((600, 400)) 11 | .create(); 12 | 13 | frame.archive_handler(resources).expect("Invalid archive"); 14 | 15 | frame.load_file("this://app/index.htm"); 16 | frame.run_app(); 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/clippy.yml: -------------------------------------------------------------------------------- 1 | name: Clippy 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - travis 8 | 9 | pull_request: 10 | branches: 11 | - master 12 | 13 | jobs: 14 | clippy: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - run: rustup component add clippy 20 | 21 | - uses: actions-rs/clippy-check@v1 22 | with: 23 | token: ${{ secrets.GITHUB_TOKEN }} 24 | -------------------------------------------------------------------------------- /examples/extension/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "extension" 3 | version = "0.1.0" 4 | description = "A simple Sciter extension library" 5 | authors = ["pravic "] 6 | homepage = "https://sciter.com/include-library-name-native-extensions/" 7 | edition = "2018" 8 | publish = false 9 | 10 | [lib] 11 | path = "src/extension.rs" 12 | crate-type = ["cdylib"] 13 | test = false 14 | bench = false 15 | 16 | [dependencies] 17 | sciter-rs = { version = "0.5", path="../../", features = ["extension"] } 18 | -------------------------------------------------------------------------------- /examples/windowless/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "windowless" 3 | version = "0.1.0" 4 | description = "Sciter.Lite windowless example" 5 | authors = ["pravic "] 6 | edition = "2018" 7 | publish = false 8 | 9 | [[bin]] 10 | name = "windowless" 11 | path = "src/windowless.rs" 12 | 13 | [dependencies] 14 | sciter-rs = { version = "0.5", path="../../", features = ["windowless", "dynamic"] } 15 | 16 | winit = "0.24" 17 | winapi = { version = "0.3", features = [ 18 | "impl-default", 19 | "winuser", 20 | "wingdi", 21 | "sysinfoapi", 22 | ] } 23 | raw-window-handle = "0.3" 24 | -------------------------------------------------------------------------------- /serde/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sciter-serde" 3 | version = "0.3.2" 4 | description = "Serde support for Sciter engine." 5 | keywords = ["serde", "gui", "gtk", "opengl", "skia"] 6 | categories = ["gui", "web-programming", "rendering::graphics-api", "api-bindings"] 7 | 8 | authors = ["pravic "] 9 | repository = "https://github.com/sciter-sdk/rust-sciter" 10 | documentation = "https://docs.rs/sciter-serde" 11 | license = "MIT" 12 | 13 | exclude = [".gitignore", ".editorconfig", ".appveyor.yml"] 14 | 15 | [badges] 16 | appveyor = { repository = "sciter-sdk/rust-sciter" } 17 | travis-ci = { repository = "sciter-sdk/rust-sciter" } 18 | 19 | [dependencies] 20 | sciter-rs = { version = "0.5" } 21 | serde = "1" 22 | 23 | [dev-dependencies] 24 | serde_derive = "1" 25 | serde_bytes = "0.11" 26 | -------------------------------------------------------------------------------- /examples/threads.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate sciter; 3 | use sciter::Value; 4 | 5 | struct EventHandler; 6 | 7 | impl EventHandler { 8 | // script handler 9 | fn exec_task(&self, task_no: i32, progress: sciter::Value, done: sciter::Value) -> bool { 10 | 11 | use std::{thread, time}; 12 | thread::spawn(move || { 13 | 14 | for i in 1..100 { 15 | // call `onProgress` callback 16 | thread::sleep(time::Duration::from_millis(100)); 17 | progress.call(None, &make_args!(i), None).unwrap(); 18 | } 19 | 20 | // call `onDone` callback 21 | done.call(None, &make_args!(task_no), None).unwrap(); 22 | }); 23 | true 24 | } 25 | } 26 | 27 | impl sciter::EventHandler for EventHandler { 28 | // route script calls to our handler 29 | dispatch_script_call! { 30 | fn exec_task(i32, Value, Value); 31 | } 32 | } 33 | 34 | fn main() { 35 | let html = include_bytes!("threads.htm"); 36 | let mut frame = sciter::WindowBuilder::main_window() 37 | .with_size((1200, 900)) 38 | .create(); 39 | frame.event_handler(EventHandler); 40 | frame.load_html(html, None); 41 | frame.run_app(); 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright 2019 pravic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/fire_event.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | Fire event demo 4 | 23 | 37 | 38 | 39 | 40 |

Fire event

41 |

Running on machine

42 | 43 | 44 | 45 | 46 | 47 |
48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /examples/extension/src/extension.rs: -------------------------------------------------------------------------------- 1 | //! Sciter extension library example. 2 | //! 3 | //! See the [blog post](https://sciter.com/include-library-name-native-extensions/). 4 | 5 | #[macro_use] 6 | extern crate sciter; 7 | 8 | use sciter::types::{BOOL, VALUE}; 9 | use sciter::Value; 10 | 11 | /// Extension entry point. 12 | #[no_mangle] 13 | pub extern "system" fn SciterLibraryInit(api: &'static sciter::ISciterAPI, exported: &mut VALUE) -> BOOL { 14 | sciter::set_host_api(api); 15 | 16 | let ext_api = vmap! { 17 | "add" => add, 18 | "sub" => sub, 19 | }; 20 | 21 | ext_api.pack_to(exported); 22 | 23 | true as BOOL 24 | } 25 | 26 | /// Calculate the sum of all the given arguments. 27 | pub fn add(args: &[Value]) -> Value { 28 | let sum: i32 = args 29 | .iter() 30 | .map(|v| v.to_int()) 31 | .filter(|v| v.is_some()) 32 | .map(|v| v.unwrap()) 33 | .sum(); 34 | 35 | sum.into() 36 | } 37 | 38 | /// `function sub(a, b) { return a - b; }` 39 | pub fn sub(args: &[Value]) -> std::result::Result { 40 | if let [a, b] = args { 41 | let a = a.to_int().ok_or("`a` is not an int")?; 42 | let b = b.to_int().ok_or("`b` is not an int")?; 43 | 44 | let result = a - b; 45 | 46 | Ok(result.into()) 47 | } else { 48 | Err(format!("sub(a,b) expects 2 parameters, given {} instead.", args.len())) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/first.rs: -------------------------------------------------------------------------------- 1 | //! An example showing various information about Sciter. 2 | 3 | extern crate sciter; 4 | 5 | fn main() { 6 | // can be called as `examples/first ~/lib/libsciter.so` 7 | if cfg!(feature = "dynamic") { 8 | if let Some(arg) = std::env::args().nth(1) { 9 | println!("using {:?}", arg); 10 | if let Err(e) = sciter::set_library(&arg) { 11 | panic!("Invalid library path specified: {}", e); 12 | } 13 | } 14 | } 15 | 16 | let arch = if cfg!(target_arch = "x86_64") { "x64" } else { "x86" }; 17 | println!("calling SciterAPI {}", arch); 18 | 19 | // bypass the ABI compatability checks (e.g. in windowless builds) 20 | let scapi = sciter::SciterAPI_unchecked(); 21 | 22 | let abi_version = scapi.version; 23 | println!("sciter abi version: {:#0x}, windowless: {}", abi_version, abi_version >= 0x0001_0001); 24 | 25 | let class_name = sciter::utf::w2s((scapi.SciterClassName)()); 26 | println!("sciter class name: {:?}", class_name); 27 | 28 | // Sciter library version 29 | use sciter::types::BOOL; 30 | let v1 = (scapi.SciterVersion)(true as BOOL); 31 | let v2 = (scapi.SciterVersion)(false as BOOL); 32 | let num = [v1 >> 16, v1 & 0xFFFF, v2 >> 16, v2 & 0xFFFF]; 33 | let version = num.iter().map(|&x| x.to_string()).collect::>().join("."); 34 | println!("sciter version: {} {:?}", version, num); 35 | } 36 | -------------------------------------------------------------------------------- /serde/src/error.rs: -------------------------------------------------------------------------------- 1 | use std; 2 | use std::fmt::{self, Display}; 3 | 4 | use serde::{ser, de}; 5 | 6 | 7 | /// Result type for serialization. 8 | pub type Result = std::result::Result; 9 | 10 | /// Error type for serialization. 11 | #[derive(Debug, Clone, PartialEq)] 12 | pub enum Error { 13 | Message(String), 14 | Unimplemented, 15 | UnsupportedType, 16 | ExpectedType(String), 17 | } 18 | 19 | impl ser::Error for Error { 20 | fn custom(msg: T) -> Self { 21 | Error::Message(msg.to_string()) 22 | } 23 | } 24 | 25 | impl de::Error for Error { 26 | fn custom(msg: T) -> Self { 27 | Error::Message(msg.to_string()) 28 | } 29 | } 30 | 31 | impl std::error::Error for Error { 32 | fn description(&self) -> &str { 33 | match *self { 34 | Error::Message(ref msg) => msg, 35 | Error::ExpectedType(ref msg) => msg, 36 | Error::Unimplemented => "unimplemented", 37 | Error::UnsupportedType => "unsupported", 38 | } 39 | } 40 | } 41 | 42 | impl Display for Error { 43 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 44 | match self { 45 | Error::Message(ref msg) => write!(f, "error: {}", msg), 46 | Error::ExpectedType(ref msg) => write!(f, "expected: {}", msg), 47 | Error::UnsupportedType => write!(f, "unsupported type"), 48 | Error::Unimplemented => write!(f, "unimplemented"), 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /examples/som.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | SOM test 4 | 7 | 61 | 62 | 63 |
Hello, body
64 |

but open Inspector to see the logs

65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /examples/fire_event.rs: -------------------------------------------------------------------------------- 1 | //! Fire event Sciter sample. 2 | #![allow(unused_variables)] 3 | #![allow(non_snake_case)] 4 | 5 | extern crate sciter; 6 | 7 | use sciter::Element; 8 | use self::sciter::dom::event::*; 9 | use self::sciter::dom::HELEMENT; 10 | use self::sciter::value::Value; 11 | 12 | struct FireEvent; 13 | 14 | impl sciter::EventHandler for FireEvent { 15 | 16 | fn on_event(&mut self, root: HELEMENT, source: HELEMENT, target: HELEMENT, code: BEHAVIOR_EVENTS, phase: PHASE_MASK, reason: EventReason) -> bool { 17 | if phase != PHASE_MASK::BUBBLING { 18 | return false; 19 | } 20 | 21 | if code == BEHAVIOR_EVENTS::BUTTON_CLICK { 22 | 23 | // `root` points to attached element, usually it is an ``. 24 | 25 | let root = Element::from(root).root(); 26 | 27 | let message = root.find_first("#message").unwrap().expect("div#message not found"); 28 | let source = Element::from(source); 29 | 30 | println!("our root is {:?}, message is {:?} and source is {:?}", root, message, source); 31 | 32 | if let Some(id) = source.get_attribute("id") { 33 | if id == "send" { 34 | 35 | // just send a simple event 36 | source.send_event(BEHAVIOR_EVENTS::CHANGE, None, Some(message.as_ptr())).expect("Failed to send event"); 37 | return true; 38 | 39 | } else if id == "fire" { 40 | 41 | // fire event with specified params 42 | let data = Value::from("Rusty param"); 43 | 44 | source.fire_event(BEHAVIOR_EVENTS::CHANGE, None, Some(message.as_ptr()), false, Some(data)).expect("Failed to fire event"); 45 | return true; 46 | } 47 | }; 48 | }; 49 | 50 | false 51 | } 52 | } 53 | 54 | fn main() { 55 | let html = include_bytes!("fire_event.htm"); 56 | let mut frame = sciter::Window::new(); 57 | frame.event_handler(FireEvent); 58 | frame.load_html(html, Some("example://fire_event.htm")); 59 | frame.run_app(); 60 | } 61 | -------------------------------------------------------------------------------- /examples/minimal.rs: -------------------------------------------------------------------------------- 1 | //! Minimalistic Sciter sample. 2 | 3 | // Specify the Windows subsystem to eliminate console window. 4 | // Requires Rust 1.18. 5 | #![windows_subsystem="windows"] 6 | 7 | extern crate sciter; 8 | 9 | fn main() { 10 | // Step 1: Include the 'minimal.html' file as a byte array. 11 | // Hint: Take a look into 'minimal.html' which contains some tiscript code. 12 | let html = include_bytes!("minimal.htm"); 13 | 14 | // Step 2: Enable the features we need in our tiscript code. 15 | sciter::set_options(sciter::RuntimeOptions::ScriptFeatures( 16 | sciter::SCRIPT_RUNTIME_FEATURES::ALLOW_SYSINFO as u8 // Enables `Sciter.machineName()`. Required for opening file dialog (`view.selectFile()`) 17 | | sciter::SCRIPT_RUNTIME_FEATURES::ALLOW_FILE_IO as u8 // Enables opening file dialog (`view.selectFile()`) 18 | )).unwrap(); 19 | 20 | // Enable debug mode for all windows, so that we can inspect them via Inspector. 21 | sciter::set_options(sciter::RuntimeOptions::DebugMode(true)).unwrap(); 22 | 23 | // Step 3: Create a new main sciter window of type `sciter::Window`. 24 | // Hint: The sciter Window wrapper (src/window.rs) contains more 25 | // interesting functions to open or attach to another existing window. 26 | let mut frame = sciter::Window::new(); 27 | 28 | if cfg!(target_os="macos") { 29 | // a temporary workaround for OSX, see 30 | // https://sciter.com/forums/topic/global-sciter_set_debug_mode-does-not-work-in-osx/ 31 | frame.set_options(sciter::window::Options::DebugMode(true)).unwrap(); 32 | } 33 | 34 | // Step 4: Load HTML byte array from memory to `sciter::Window`. 35 | // Hint: second parameter is an optional uri, it can be `None` in simple cases, 36 | // but it is useful for debugging purposes (check the Inspector tool from the Sciter SDK). 37 | // Also you can use a `load_file` method, but it requires an absolute path 38 | // of the main document to resolve HTML resources properly. 39 | frame.load_html(html, Some("example://minimal.htm")); 40 | 41 | // Step 5: Show window and run the main app message loop until window been closed. 42 | frame.run_app(); 43 | } 44 | -------------------------------------------------------------------------------- /examples/download.rs: -------------------------------------------------------------------------------- 1 | //! Download http content (Go sciter example port). 2 | #![allow(dead_code)] 3 | 4 | extern crate sciter; 5 | 6 | use sciter::dom::HELEMENT; 7 | use sciter::host; 8 | use sciter::utf; 9 | use std::rc::{Rc, Weak}; 10 | 11 | struct Handler { 12 | host: Weak, 13 | } 14 | 15 | impl sciter::EventHandler for Handler { 16 | fn document_complete(&mut self, _root: HELEMENT, _target: HELEMENT) { 17 | if let Some(host) = self.host.upgrade() { 18 | // eval script inside the document to receive a "user@machine" string. 19 | let result = host.eval_script("[Sciter.userName(), Sciter.machineName(true)].join(`@`)"); 20 | match result { 21 | Ok(name) => { 22 | println!("running on {}", name); 23 | } 24 | Err(e) => { 25 | println!("error! {}", e.as_string().unwrap_or("?".to_string())); 26 | } 27 | } 28 | } 29 | } 30 | } 31 | 32 | impl sciter::HostHandler for Handler { 33 | fn on_data_loaded(&mut self, pnm: &host::SCN_DATA_LOADED) { 34 | println!("data loaded, uri: `{}`, {} bytes.", utf::w2s(pnm.uri), pnm.dataSize); 35 | } 36 | 37 | fn on_attach_behavior(&mut self, pnm: &mut host::SCN_ATTACH_BEHAVIOR) -> bool { 38 | let el = sciter::Element::from(pnm.element); 39 | let name = utf::u2s(pnm.name); 40 | println!("{}: behavior {}", el, name); 41 | false 42 | } 43 | } 44 | 45 | impl Drop for Handler { 46 | fn drop(&mut self) { 47 | // called 2 times because it is created 2 times 48 | println!("Good bye, window"); 49 | } 50 | } 51 | 52 | fn main() { 53 | let mut frame = sciter::WindowBuilder::main_window().with_size((1024, 768)).create(); 54 | 55 | // Can't use something like `frame.sciter_handler(Rc::new(handler))` yet. 56 | let handler = Handler { 57 | host: Rc::downgrade(&frame.get_host()), 58 | }; 59 | frame.sciter_handler(handler); 60 | 61 | let handler = Handler { 62 | host: Rc::downgrade(&frame.get_host()), 63 | }; 64 | frame.event_handler(handler); 65 | 66 | frame.set_title("Download sample"); 67 | frame.load_file("http://httpbin.org/html"); 68 | frame.run_app(); 69 | } 70 | -------------------------------------------------------------------------------- /serde/tests/deserialization.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_variables)] 2 | 3 | extern crate sciter; 4 | extern crate sciter_serde; 5 | 6 | #[macro_use] 7 | extern crate serde_derive; 8 | extern crate serde_bytes; 9 | extern crate serde; 10 | 11 | use sciter::{Value}; 12 | use sciter_serde::{from_value, to_value}; 13 | 14 | 15 | #[test] 16 | fn basic_types() { 17 | // bool 18 | let v: bool = from_value(&Value::from(true)).unwrap(); 19 | assert_eq!(v, true); 20 | 21 | // integer types 22 | let v: i32 = from_value(&Value::from(0)).unwrap(); 23 | assert_eq!(v, 0); 24 | 25 | let v: i32 = from_value(&Value::from(7i32)).unwrap(); 26 | assert_eq!(v, 7i32); 27 | 28 | // float 29 | let v: f32 = from_value(&Value::from(7.0)).unwrap(); 30 | assert_eq!(v, 7.0); 31 | 32 | let v: f64 = from_value(&Value::from(7.0)).unwrap(); 33 | assert_eq!(v, 7.0); 34 | 35 | // Option 36 | let v = Value::null(); 37 | let v: Option = from_value(&v).unwrap(); 38 | assert_eq!(v, None); 39 | 40 | let v = Value::from(7); 41 | let v: Option = from_value(&v).unwrap(); 42 | assert_eq!(v, Some(7)); 43 | } 44 | 45 | #[test] 46 | fn strings() { 47 | let v: char = from_value(&Value::from("7")).unwrap(); 48 | assert_eq!(v, '7'); 49 | 50 | let v: String = from_value(&Value::from("7")).unwrap(); 51 | assert_eq!(v, "7"); 52 | 53 | let v: serde_bytes::ByteBuf = from_value(&Value::from(b"hello".as_ref())).unwrap(); 54 | let v: &[u8] = &v; 55 | assert_eq!(v, b"hello".as_ref()); 56 | } 57 | 58 | #[test] 59 | fn arrays() { 60 | let it = [1,2,3].iter(); 61 | let v: Value = it.cloned().collect(); 62 | let v: Vec = from_value(&v).unwrap(); 63 | assert_eq!(v, &[1,2,3]); 64 | } 65 | 66 | #[test] 67 | fn structs() { 68 | #[derive(Serialize, Deserialize, PartialEq, Debug)] 69 | struct Test { 70 | int: u32, 71 | seq: Vec, 72 | } 73 | 74 | println!(""); 75 | 76 | let a = Test { int: 7, seq: vec!["a".to_owned(), "b".to_owned()]}; 77 | 78 | let v: Value = to_value(&a).unwrap(); 79 | println!("serialized Test:\n {:?}", v); 80 | 81 | println!("keys:"); 82 | v.keys().inspect(|i| println!(" {:?}", i)).count(); 83 | 84 | println!("values:"); 85 | v.values().inspect(|i| println!(" {:?}", i)).count(); 86 | 87 | println!("items:"); 88 | v.items().iter().inspect(|i| println!(" {:?}", i)).count(); 89 | 90 | let e: Test = from_value(&v).unwrap(); 91 | println!("deserialized Test:\n {:?}", e); 92 | 93 | assert_eq!(a, e); 94 | } 95 | -------------------------------------------------------------------------------- /.appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 0.5.0.{build} 2 | 3 | branches: 4 | only: 5 | - master 6 | - travis 7 | 8 | image: 9 | - Visual Studio 2017 10 | 11 | environment: 12 | matrix: 13 | - TARGET: x86_64-pc-windows-msvc 14 | CHANNEL: stable 15 | ARCH: 64 16 | 17 | - TARGET: i686-pc-windows-msvc 18 | CHANNEL: stable 19 | ARCH: 32 20 | 21 | - TARGET: x86_64-pc-windows-msvc 22 | CHANNEL: stable 23 | ARCH: 64skia 24 | 25 | - TARGET: i686-pc-windows-msvc 26 | CHANNEL: stable 27 | ARCH: 32skia 28 | 29 | - TARGET: x86_64-pc-windows-msvc 30 | CHANNEL: stable 31 | ARCH: 64 32 | FEATURES: --features "dynamic" 33 | 34 | - TARGET: i686-pc-windows-msvc 35 | CHANNEL: stable 36 | ARCH: 32 37 | FEATURES: --features "dynamic" 38 | 39 | - TARGET: x86_64-pc-windows-msvc 40 | CHANNEL: nightly 41 | ARCH: 64 42 | 43 | - TARGET: i686-pc-windows-msvc 44 | CHANNEL: nightly 45 | ARCH: 32 46 | 47 | - TARGET: x86_64-pc-windows-msvc 48 | CHANNEL: 1.46.0 49 | ARCH: 64 50 | 51 | - TARGET: i686-pc-windows-msvc 52 | CHANNEL: 1.46.0 53 | ARCH: 32 54 | 55 | - TARGET: x86_64-pc-windows-msvc 56 | CHANNEL: 1.46.0 57 | ARCH: 64 58 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 59 | 60 | 61 | cache: 62 | - C:\Users\appveyor\.cargo\registry 63 | #- C:\projects\deps -> appveyor.yml 64 | #- target 65 | 66 | install: 67 | - cmd: echo Testing sciter%ARCH% with Rust %CHANNEL%. 68 | - cmd: echo Current directory is %APPVEYOR_BUILD_FOLDER% 69 | - cmd: mkdir ..\deps 70 | - curl -sSLo "..\deps\sciter.dll" "https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x%ARCH%/sciter.dll" 71 | - curl -sSLo "..\deps\rustup-init.exe" "https://win.rustup.rs/" 72 | - ..\deps\rustup-init.exe -y --default-host %TARGET% --default-toolchain %CHANNEL% 73 | - cmd: set PATH=%PATH%;C:\Users\appveyor\.cargo\bin;C:\projects\deps 74 | 75 | before_build: 76 | - cmd: cd 77 | - rustc --version 78 | - cargo update 79 | 80 | build_script: 81 | - cmd: echo Building library 82 | - cargo build --release --all %FEATURES% 83 | 84 | - cmd: echo Building examples 85 | - cargo build --example first 86 | - cargo build --release --examples %FEATURES% 87 | 88 | test_script: 89 | - cargo run --example first %FEATURES% 90 | - cargo run --example first %FEATURES% 91 | - cargo run --example first %FEATURES% -- C:/projects/deps/sciter.dll 92 | 93 | - cargo test -p sciter-rs %FEATURES% 94 | - cargo test -p sciter-rs %FEATURES% --release 95 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Based on the "trust" template v0.1.2 2 | # https://github.com/japaric/trust/tree/v0.1.2 3 | 4 | # Ubuntu versions: 5 | # https://docs.travis-ci.com/user/reference/linux/ 6 | dist: xenial 7 | sudo: false 8 | language: rust 9 | compiler: gcc 10 | 11 | os: 12 | - linux 13 | - osx 14 | 15 | rust: 16 | - stable 17 | - nightly 18 | - 1.46.0 19 | 20 | matrix: 21 | include: 22 | - os: osx 23 | osx_image: xcode8 24 | - os: osx 25 | osx_image: xcode11 26 | 27 | branches: 28 | only: 29 | - master 30 | - travis 31 | 32 | notifications: 33 | email: change 34 | 35 | 36 | cache: cargo 37 | before_cache: 38 | # Travis can't cache files that are not readable by "others" 39 | - chmod -R a+r $HOME/.cargo 40 | 41 | addons: 42 | apt: 43 | sources: 44 | - ubuntu-toolchain-r-test 45 | 46 | packages: 47 | - libgtk-3-dev 48 | - libgtk-3-0 49 | - libstdc++-6-pic 50 | 51 | 52 | before_install: 53 | - set -e 54 | - rustup self update 55 | 56 | install: 57 | - source ~/.cargo/env || true 58 | - export SDK_URL=https://raw.githubusercontent.com/c-smile/sciter-sdk/master 59 | - if [ "$TRAVIS_OS_NAME" = "osx" ]; then export SDK_DLL="$TRAVIS_BUILD_DIR/libsciter.dylib"; fi 60 | - if [ "$TRAVIS_OS_NAME" = "linux" ]; then export SDK_DLL="$TRAVIS_BUILD_DIR/libsciter-gtk.so"; fi 61 | 62 | - if [ "$TRAVIS_OS_NAME" = "osx" ]; then curl -so "$SDK_DLL" $SDK_URL/bin.osx/libsciter.dylib; fi 63 | - if [ "$TRAVIS_OS_NAME" = "linux" ]; then curl -so "$SDK_DLL" $SDK_URL/bin.lnx/x64/libsciter-gtk.so; fi 64 | 65 | before_script: 66 | - if [ "$TRAVIS_OS_NAME" = "osx" ]; then export DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH:$TRAVIS_BUILD_DIR"; fi 67 | 68 | - if [ "$TRAVIS_OS_NAME" = "linux" ]; then export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$TRAVIS_BUILD_DIR"; fi 69 | - if [ "$TRAVIS_OS_NAME" = "linux" ]; then export RUSTFLAGS='-C link-arg=-Wl,--unresolved-symbols=ignore-in-shared-libs'; fi 70 | 71 | - export PATH="$PATH:$TRAVIS_BUILD_DIR" 72 | - export LIBRARY_PATH="$LIBRARY_PATH:$TRAVIS_BUILD_DIR" 73 | - export RUST_BACKTRACE=full 74 | 75 | - #ls /usr/lib/x86_64-linux-gnu/libstdc++* 76 | - #strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBC 77 | - #file $SDK_DLL 78 | - gcc --version 79 | - rustc --version 80 | 81 | script: 82 | - cargo update 83 | 84 | - cargo run --example first 85 | - cargo run --example first --features "dynamic" 86 | - cargo run --example first --features "dynamic" -- "$SDK_DLL" 87 | 88 | - cargo build --all 89 | - cargo build --all --release 90 | - cargo build --examples --release 91 | 92 | - cargo test -p sciter-rs 93 | - cargo test -p sciter-rs --release 94 | 95 | after_script: set +e 96 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sciter-rs" 3 | version = "0.5.58" 4 | description = "Rust bindings for Sciter - Embeddable HTML/CSS/script engine (cross-platform desktop GUI toolkit). Also capable with DirectX / OpenGL." 5 | keywords = ["gui", "gtk", "cocoa", "opengl", "skia"] 6 | categories = ["gui", "web-programming", "rendering::graphics-api", "api-bindings"] 7 | 8 | authors = ["pravic "] 9 | repository = "https://github.com/sciter-sdk/rust-sciter" 10 | documentation = "https://docs.rs/sciter-rs" 11 | readme = "README.md" 12 | license = "MIT" 13 | 14 | exclude = [".gitignore", ".editorconfig", ".appveyor.yml", "clippy.toml"] 15 | 16 | [badges] 17 | appveyor = { repository = "sciter-sdk/rust-sciter" } 18 | travis-ci = { repository = "sciter-sdk/rust-sciter" } 19 | 20 | maintenance = { status = "passively-maintained" } 21 | 22 | [workspace] 23 | members = [".", "serde", "examples/extension", "examples/windowless"] 24 | 25 | 26 | [lib] 27 | name = "sciter" 28 | path = "src/lib.rs" 29 | crate-type = ["rlib"] 30 | 31 | [features] 32 | default = ["dynamic"] 33 | 34 | # Enable nightly compiler features (currently doesn't use any). 35 | nightly = [] 36 | 37 | # Build as a Sciter extension library. 38 | # see "examples/extension" 39 | # note: this feature can't be tested. 40 | extension = [] 41 | 42 | # Load Sciter DLL dynamically from the path specified by `sciter::set_library`. 43 | # Otherwise, links statically to `libsciter-gtk.so` or `libsciter.dylib`. 44 | dynamic = [] 45 | 46 | # Build this crate specifically for Sciter.Lite versions 47 | # which are incompatible with the regular ones. 48 | windowless = [] 49 | 50 | 51 | [dependencies] 52 | libc = "0.2" 53 | lazy_static = "1.0" 54 | 55 | [target.'cfg(target_vendor = "apple")'.dependencies] 56 | objc = "0.2" 57 | objc-foundation = "0.1" 58 | 59 | [[example]] 60 | name = "first" 61 | path = "examples/first.rs" 62 | 63 | [[example]] 64 | name = "minimal" 65 | path = "examples/minimal.rs" 66 | 67 | [[example]] 68 | name = "download" 69 | path = "examples/download.rs" 70 | 71 | [[example]] 72 | name = "dom" 73 | path = "examples/dom.rs" 74 | 75 | [[example]] 76 | name = "fire_event" 77 | path = "examples/fire_event.rs" 78 | 79 | [[example]] 80 | name = "interop" 81 | path = "examples/interop.rs" 82 | 83 | [[example]] 84 | name = "threads" 85 | path = "examples/threads.rs" 86 | 87 | [[example]] 88 | name = "archived" 89 | path = "examples/archived.rs" 90 | 91 | [[example]] 92 | name = "video" 93 | path = "examples/video.rs" 94 | 95 | [[example]] 96 | name = "clock" 97 | path = "examples/clock.rs" 98 | 99 | [[example]] 100 | name = "som" 101 | path = "examples/som.rs" 102 | -------------------------------------------------------------------------------- /src/capi/schandler.rs: -------------------------------------------------------------------------------- 1 | //! Native handler wrappers. 2 | 3 | #![allow(dead_code)] 4 | 5 | use capi::sctypes::{LPCVOID, LPVOID}; 6 | 7 | type Opaque = LPCVOID; 8 | 9 | 10 | /// Native wrapper for handlers which can be passed to foreign functions. 11 | #[repr(C)] 12 | #[derive(Debug)] 13 | pub struct NativeHandler { 14 | // pointer to handler 15 | handler: Opaque, 16 | 17 | // pointer to handler destructor 18 | dtor: fn(param: Opaque), 19 | } 20 | 21 | impl Drop for NativeHandler { 22 | fn drop(&mut self) { 23 | if !self.handler.is_null() { 24 | (self.dtor)(self.handler); 25 | } 26 | } 27 | } 28 | 29 | impl Default for NativeHandler { 30 | fn default() -> Self { 31 | NativeHandler { handler: ::std::ptr::null(), dtor: NativeHandler::drop_it:: } 32 | } 33 | } 34 | 35 | impl NativeHandler { 36 | 37 | /// Construct boxed wrapper from handler object. 38 | pub fn from(handler: T) -> NativeHandler { 39 | let boxed = Box::new(handler); 40 | let ptr = Box::into_raw(boxed); 41 | let dtor = NativeHandler::drop_it::; 42 | return NativeHandler { handler: ptr as Opaque, dtor: dtor }; 43 | } 44 | 45 | /// Return a native pointer to handler wrapper. 46 | pub fn as_ptr(&self) -> LPCVOID { 47 | self.handler as LPCVOID 48 | } 49 | 50 | /// Return a native pointer to handler wrapper. 51 | pub fn as_mut_ptr(&self) -> LPVOID { 52 | self.handler as LPVOID 53 | } 54 | 55 | /// Access handler by reference. 56 | pub fn as_ref(&self) -> &T { 57 | let pobj = self.handler as *const T; 58 | let boxed = unsafe { &*pobj }; 59 | return boxed; 60 | } 61 | 62 | /// Access handler by mutable reference. 63 | pub fn as_mut(&mut self) -> &mut T { 64 | let pobj = self.handler as *mut T; 65 | let boxed = unsafe { &mut *pobj }; 66 | return boxed; 67 | } 68 | 69 | #[allow(clippy::mut_from_ref)] 70 | pub fn get_data(ptr: &LPVOID) -> &mut T { 71 | assert!(!ptr.is_null()); 72 | let obj = *ptr as *mut T; 73 | unsafe { &mut *obj} 74 | } 75 | 76 | // Call destructor of handler. 77 | fn drop_it(param: Opaque) { 78 | // reconstruct pointer to Box 79 | let pobj = param as *mut T; 80 | if !pobj.is_null() { 81 | // and drop it 82 | unsafe { Box::from_raw(pobj) }; 83 | } 84 | } 85 | } 86 | 87 | #[cfg(test)] 88 | mod test { 89 | use super::NativeHandler; 90 | 91 | struct Handler { 92 | pub i: i32, 93 | } 94 | 95 | impl Drop for Handler { 96 | fn drop(&mut self) { 97 | println!("Handler::drop"); 98 | } 99 | } 100 | 101 | 102 | 103 | #[test] 104 | fn test1() { 105 | { 106 | println!("\ncreate"); 107 | let h = Handler { i: 7 }; 108 | let p = NativeHandler::from(h); 109 | 110 | println!("handler i {:?}", p.as_ref::().i); 111 | println!("quit"); 112 | } 113 | println!("done."); 114 | 115 | // assert!(false); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /examples/interop.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | Rust-sciter sample 4 | 16 | 77 | 78 | 79 | 80 |

Rust Sciter Application

81 |

Running on machine via ().

82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /serde/tests/serialization.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_variables)] 2 | 3 | extern crate sciter; 4 | extern crate sciter_serde; 5 | 6 | #[macro_use] 7 | extern crate serde_derive; 8 | extern crate serde_bytes; 9 | extern crate serde; 10 | 11 | use sciter::{Value}; 12 | use sciter_serde::{to_value}; 13 | 14 | 15 | #[test] 16 | fn basic_types() { 17 | // bool 18 | let v = to_value(&true).unwrap(); 19 | assert!(v.is_bool()); 20 | assert_eq!(v, Value::from(true)); 21 | 22 | // integer types 23 | let v = to_value(&0).unwrap(); 24 | assert!(v.is_int()); 25 | assert_eq!(v.to_int(), Some(0)); 26 | 27 | let v = to_value(&7u8).unwrap(); 28 | assert_eq!(v, Value::from(7)); 29 | 30 | let v = to_value(&7u16).unwrap(); 31 | assert_eq!(v, Value::from(7)); 32 | 33 | let v = to_value(&7u32).unwrap(); 34 | assert_eq!(v, Value::from(7)); 35 | 36 | let v = to_value(&7i8).unwrap(); 37 | assert_eq!(v, Value::from(7)); 38 | 39 | let v = to_value(&7i16).unwrap(); 40 | assert_eq!(v, Value::from(7)); 41 | 42 | let v = to_value(&7i32).unwrap(); 43 | assert_eq!(v, Value::from(7)); 44 | 45 | let v = to_value(&7.0).unwrap(); 46 | assert!(v.is_float()); 47 | 48 | // 64-bit 49 | // let v = to_value(&7u64).unwrap(); 50 | // assert!(v.is_float()); 51 | // assert_eq!(v, Value::from(7.0)); 52 | 53 | // Option 54 | // let v = to_value(&Some(7)).unwrap(); 55 | // assert!(v.is_int()); 56 | 57 | // let v = to_value(&None).unwrap(); 58 | // assert!(v.is_null()); 59 | } 60 | 61 | #[test] 62 | fn strings() { 63 | // strings 64 | let v = to_value(&'h').unwrap(); 65 | assert!(v.is_string()); 66 | assert_eq!(v, Value::from("h")); 67 | 68 | let v = to_value("hello").unwrap(); 69 | assert!(v.is_string()); 70 | assert_eq!(v, Value::from("hello")); 71 | 72 | // doesn't work because Rust doesn't have specialization yet (https://github.com/rust-lang/rust#31844) 73 | // let v = to_value(b"hello").unwrap(); 74 | // println!("b'hello': {:?}", v); 75 | // assert!(v.is_bytes()); 76 | // assert_eq!(v.as_bytes(), Some(b"hello".as_ref())); 77 | 78 | use serde_bytes::Bytes; 79 | 80 | let v = to_value(&Bytes::new(b"hello")).unwrap(); 81 | assert!(v.is_bytes()); 82 | assert_eq!(v.as_bytes(), Some(b"hello".as_ref())); 83 | } 84 | 85 | #[test] 86 | fn arrays() { 87 | let a = [1,2,3]; 88 | let v = to_value(&a).unwrap(); 89 | assert!(v.is_array()); 90 | assert_eq!(v.len(), a.len()); 91 | 92 | let a = vec![1,2,3]; 93 | let v = to_value(&a).unwrap(); 94 | assert!(v.is_array()); 95 | assert_eq!(v.len(), a.len()); 96 | } 97 | 98 | #[test] 99 | fn structs() { 100 | 101 | #[derive(Serialize)] 102 | struct Test { 103 | int: u32, 104 | seq: Vec<&'static str>, 105 | } 106 | 107 | let a = Test { int: 7, seq: vec!["a", "b"]}; 108 | let v = to_value(&a).unwrap(); 109 | assert!(v.is_map()); 110 | assert_eq!(v.len(), 2); 111 | assert_eq!(v.get_item("int"), Value::from(7) ); 112 | assert_eq!(v.get_item("seq").len(), 2); 113 | } 114 | -------------------------------------------------------------------------------- /examples/threads.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | Threads demo 4 | 13 | 32 | 33 | 34 |

Sciter UI, threads demo

35 |
36 |
37 | 38 | 39 |
40 |
41 |

The Start Task onClick handler is defined as

42 |
43 | $(#start-task).onClick = function()
44 | {
45 |   var taskElem = $(div#tasks > select)
46 |       .$append(<option>Task { ++taskNo }
47 |                <progress max=100 />
48 |                <span.result /></option>);
49 |   function onProgress(p100) {
50 |     taskElem.$(progress).value = p100;
51 |   }
52 |   function onDone(taskId) {
53 |     taskElem.$(span.result).text = "Done!";
54 |     taskElem.$(progress).remove();
55 |   }
56 |   view.exec_task(taskId, onProgress, onDone);
57 | }
58 |       
59 | 60 |

It defines couple of callback functions and calls view.exec_task() with them.

61 |

The view.exec_task() native method is implemented in EventHandler::exec_task().

62 |

The EventHandler::exec_task() starts worker thread passing taskNo, onProgress and 63 | onDone parameters to it.

64 |

Worker thread body is defined in Rust code as:

65 |
66 | // worker thread body, simulate time consuming task
67 | fn thread_body(task_no: i32, progress: Value, done: Value)
68 | {
69 |   for i in 1..100 {
70 |     std::thread::sleep(std::time::Duration::from_millis(100));
71 |     progress.call(None, &make_args!(i), None).unwrap(); // report task progress
72 |   }
73 |   // report task completion,
74 |   // we can pass some result data here, for now just taskId
75 |   done.call(None, &make_args!(task_no), None).unwrap();
76 | }
77 |       
78 |

As you see it calls passed callback functions.

79 |
80 |
81 | 82 | 83 | -------------------------------------------------------------------------------- /.github/workflows/sciter-tis.yml: -------------------------------------------------------------------------------- 1 | name: TIScript 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - travis 8 | 9 | pull_request: 10 | branches: 11 | - master 12 | 13 | # Look: 14 | # https://github.com/actions/starter-workflows/blob/master/ci/rust.yml 15 | # 16 | # Simple, right? Right. 17 | # But we need to: 18 | # * download a specific Sciter library matching the running OS 19 | # * figure out where to save it 20 | # * add it to the $PATH 21 | # 22 | # yet, 23 | # * in case of macOS realize that it doesn't have Rust installed, so 24 | # * install it manually and don't forget to add cargo and rustc to the $PATH on each step 25 | # * and in case of Linux install additional packages for GTK3 26 | # 27 | # So, now we're ended up with this ugly script. 28 | 29 | jobs: 30 | build: 31 | name: Build and test 32 | 33 | runs-on: ${{ matrix.os }} 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | os: [macos-latest, ubuntu-latest, windows-latest] 38 | 39 | steps: 40 | - uses: actions/checkout@v2 41 | 42 | - name: Windows deps 43 | if: runner.os == 'Windows' 44 | # Windows: download sciter library 45 | run: curl -sSLo "%SCITER_DEPS%/sciter.dll" "https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.win/x64/sciter.dll" 46 | shell: cmd 47 | env: 48 | SCITER_DEPS: ${{ runner.workspace }} 49 | 50 | - name: Linux deps 51 | if: runner.os == 'Linux' 52 | # Linux: download sciter library && install libgtk-3-dev 53 | run: | 54 | curl -so "$SCITER_DEPS/libsciter-gtk.so" "https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so" 55 | sudo apt-get update -y && sudo apt-get install libgtk-3-dev libgtk-3-0 -y 56 | env: 57 | SCITER_DEPS: ${{ runner.workspace }} 58 | 59 | - name: macOS deps 60 | if: runner.os == 'macOS' 61 | # OSX: download sciter library 62 | run: | 63 | curl -so "$SCITER_DEPS/libsciter.dylib" "https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.osx/libsciter.dylib" 64 | env: 65 | SCITER_DEPS: ${{ runner.workspace }} 66 | 67 | - name: Build 68 | shell: bash 69 | run: | 70 | cargo build --all 71 | cargo build --examples 72 | 73 | - name: serde 74 | shell: bash 75 | continue-on-error: true 76 | run: | 77 | export PATH="$PATH:$SCITER_DEPS" 78 | cargo build -p sciter-serde 79 | cargo test -p sciter-serde 80 | env: 81 | SCITER_DEPS: ${{ runner.workspace }} 82 | 83 | - name: windowless 84 | shell: bash 85 | continue-on-error: true 86 | run: | 87 | cargo build -p windowless 88 | 89 | - name: extension 90 | shell: bash 91 | continue-on-error: true 92 | run: | 93 | cargo build -p extension 94 | 95 | - name: Tests 96 | shell: bash 97 | run: | 98 | export PATH="$PATH:$SCITER_DEPS" 99 | cargo run --example first 100 | cargo test -p sciter-rs 101 | env: 102 | SCITER_DEPS: ${{ runner.workspace }} 103 | -------------------------------------------------------------------------------- /src/capi/sctypes.rs: -------------------------------------------------------------------------------- 1 | //! Sciter platform-dependent types. 2 | 3 | #![allow(non_camel_case_types, non_snake_case)] 4 | 5 | extern crate libc; 6 | 7 | use self::libc::*; 8 | 9 | 10 | // common 11 | MAKE_HANDLE!(#[doc = "Window native handle."] HWINDOW, _HWINDOW); // HWND or NSView* or GtkWidget* 12 | MAKE_HANDLE!(#[doc = "Archive native handle."] HSARCHIVE, _HSARCHIVE); 13 | 14 | pub type BYTE = u8; 15 | pub type INT = i32; 16 | pub type LONG = i32; 17 | pub type UINT = u32; 18 | pub type INT64 = i64; 19 | pub type UINT64 = u64; 20 | 21 | pub type FLOAT_VALUE = f64; 22 | 23 | pub type WPARAM = size_t; 24 | pub type LPARAM = ssize_t; 25 | 26 | pub type UINT_PTR = uintptr_t; 27 | pub type LRESULT = ssize_t; 28 | 29 | pub type CHAR = c_char; 30 | pub type LPSTR = *mut CHAR; 31 | pub type LPCSTR = *const CHAR; 32 | 33 | pub type WCHAR = u16; 34 | pub type LPWSTR = *mut WCHAR; 35 | pub type LPCWSTR = *const WCHAR; 36 | 37 | pub type LPCBYTE = *const BYTE; 38 | pub type LPUINT = *mut UINT; 39 | 40 | pub type VOID = c_void; 41 | pub type LPVOID = *mut VOID; 42 | pub type LPCVOID = *const VOID; 43 | 44 | #[cfg(windows)] 45 | pub type BOOL = i32; 46 | 47 | #[cfg(not(windows))] 48 | pub type BOOL = i8; 49 | 50 | pub type PBOOL = *mut BOOL; 51 | 52 | /// Defines the coordinates of the upper-left and lower-right corners of a rectangle. 53 | #[repr(C)] 54 | #[derive(Clone, Copy, PartialEq)] 55 | #[derive(Default, Debug)] 56 | pub struct RECT { 57 | pub left: LONG, 58 | pub top: LONG, 59 | pub right: LONG, 60 | pub bottom: LONG, 61 | } 62 | pub type LPRECT = *mut RECT; 63 | pub type LPCRECT = *const RECT; 64 | 65 | impl RECT { 66 | /// Calculate the height of the rect. 67 | pub fn height(&self) -> LONG { 68 | self.bottom - self.top 69 | } 70 | 71 | /// Calculate the width of the rect. 72 | pub fn width(&self) -> LONG { 73 | self.right - self.left 74 | } 75 | 76 | /// Return the size of the rect in width and height form. 77 | pub fn size(&self) -> SIZE { 78 | SIZE { 79 | cx: self.width(), 80 | cy: self.height(), 81 | } 82 | } 83 | 84 | /// Returns the top-left point of the rect. 85 | pub fn topleft(&self) -> POINT { 86 | POINT { 87 | x: self.left, 88 | y: self.top, 89 | } 90 | } 91 | } 92 | 93 | /// Defines the `x` and `y` coordinates of a point. 94 | #[repr(C)] 95 | #[derive(Clone, Copy, PartialEq)] 96 | #[derive(Default, Debug)] 97 | pub struct POINT { 98 | pub x: LONG, 99 | pub y: LONG, 100 | } 101 | pub type LPPOINT = *mut POINT; 102 | 103 | /// Specifies the width and height of a rectangle. 104 | #[repr(C)] 105 | #[derive(Clone, Copy, PartialEq)] 106 | #[derive(Default, Debug)] 107 | pub struct SIZE { 108 | pub cx: LONG, 109 | pub cy: LONG, 110 | } 111 | pub type LPSIZE = *mut SIZE; 112 | 113 | 114 | #[cfg(windows)] 115 | #[repr(C)] 116 | #[derive(Debug)] 117 | pub struct MSG { 118 | pub hwnd: HWINDOW, 119 | pub message: UINT, 120 | pub wParam: WPARAM, 121 | pub lParam: LPARAM, 122 | pub time: UINT, 123 | pub pt: POINT, 124 | } 125 | 126 | #[cfg(windows)] 127 | pub type LPMSG = *mut MSG; 128 | 129 | #[cfg(not(windows))] 130 | pub type LPMSG = LPVOID; 131 | -------------------------------------------------------------------------------- /.github/workflows/sciter-js.yml: -------------------------------------------------------------------------------- 1 | name: JavaScript 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - travis 8 | 9 | pull_request: 10 | branches: 11 | - master 12 | 13 | # Look: 14 | # https://github.com/actions/starter-workflows/blob/master/ci/rust.yml 15 | # 16 | # Simple, right? Right. 17 | # But we need to: 18 | # * download a specific Sciter library matching the running OS 19 | # * figure out where to save it 20 | # * add it to the $PATH 21 | # 22 | # yet, 23 | # * in case of macOS realize that it doesn't have Rust installed, so 24 | # * install it manually and don't forget to add cargo and rustc to the $PATH on each step 25 | # * and in case of Linux install additional packages for GTK3 26 | # 27 | # So, now we're ended up with this ugly script. 28 | 29 | jobs: 30 | build: 31 | name: Build and test 32 | 33 | runs-on: ${{ matrix.os }} 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | os: [macos-latest, ubuntu-latest, windows-latest] 38 | 39 | steps: 40 | - uses: actions/checkout@v2 41 | 42 | - name: Windows deps 43 | if: runner.os == 'Windows' 44 | # Windows: download sciter library 45 | run: curl -sSLo "%SCITER_DEPS%/sciter.dll" "https://raw.githubusercontent.com/c-smile/sciter-js-sdk/main/bin/windows/x64/sciter.dll" 46 | shell: cmd 47 | env: 48 | SCITER_DEPS: ${{ runner.workspace }} 49 | 50 | - name: Linux deps 51 | if: runner.os == 'Linux' 52 | # Linux: download sciter library && install libgtk-3-dev 53 | run: | 54 | curl -so "$SCITER_DEPS/libsciter-gtk.so" "https://raw.githubusercontent.com/c-smile/sciter-js-sdk/main/bin/linux/x64/libsciter-gtk.so" 55 | sudo apt-get update -y && sudo apt-get install libgtk-3-dev libgtk-3-0 -y 56 | env: 57 | SCITER_DEPS: ${{ runner.workspace }} 58 | 59 | - name: macOS deps 60 | if: runner.os == 'macOS' 61 | # OSX: download sciter library 62 | run: | 63 | curl -so "$SCITER_DEPS/libsciter.dylib" "https://raw.githubusercontent.com/c-smile/sciter-js-sdk/main/bin/macosx/libsciter.dylib" 64 | env: 65 | SCITER_DEPS: ${{ runner.workspace }} 66 | 67 | - name: Build 68 | shell: bash 69 | run: | 70 | cargo build --all 71 | cargo build --examples 72 | 73 | - name: serde 74 | shell: bash 75 | continue-on-error: true 76 | run: | 77 | export PATH="$PATH:$SCITER_DEPS" 78 | cargo build -p sciter-serde 79 | cargo test -p sciter-serde 80 | env: 81 | SCITER_DEPS: ${{ runner.workspace }} 82 | 83 | - name: windowless 84 | shell: bash 85 | continue-on-error: true 86 | run: | 87 | cargo build -p windowless 88 | 89 | - name: extension 90 | shell: bash 91 | continue-on-error: true 92 | run: | 93 | cargo build -p extension 94 | 95 | - name: Tests 96 | shell: bash 97 | run: | 98 | export PATH="$PATH:$SCITER_DEPS" 99 | cargo run --example first 100 | cargo test -p sciter-rs 101 | env: 102 | SCITER_DEPS: ${{ runner.workspace }} 103 | -------------------------------------------------------------------------------- /serde/src/lib.rs: -------------------------------------------------------------------------------- 1 | // This component uses Sciter Engine, 2 | // copyright Terra Informatica Software, Inc. 3 | // (http://terrainformatica.com/). 4 | 5 | /*! 6 | 7 | [Serde](https://docs.rs/serde) support for [Sciter](https://docs.rs/sciter-rs) engine. 8 | 9 | While technically you could just use the `serde_json` crate and perform serialization via 10 | an intermediate string (something like `sciter::Value::from_str(&serde_json::to_string()?)?`), 11 | you can also use direct serialization between your data and `sciter::Value`. 12 | 13 | ## Supported types of Sciter value 14 | 15 | + Bool (`bool`) 16 | + Integer (`i8`-`i32`) 17 | + Float (`f32`-`f64`) 18 | + String (`&str`, `String`) 19 | + Bytes (`&[u8]`) 20 | + Array (`&[T]`, `Vec`) 21 | + Object (key-value mapping like `struct` or `HashMap`, `BTreeMap`, etc.) 22 | 23 | Unsupported: 24 | 25 | - Date 26 | - Currency 27 | - Length 28 | - Range 29 | - Duration 30 | - Angle 31 | - Color 32 | 33 | ## Supported types of the Serde data model 34 | 35 | * [x] `bool` 36 | * [x] integer types except the following: 37 | * [-] `i64`/`u64` - 64-bit integers stored as `f64` in Sciter 38 | * [x] strings 39 | * [x] byte arrays 40 | * [x] option 41 | * [x] unit (stored as `null`) 42 | * [x] unit struct (stored as `null`) 43 | * [x] unit variant (aka `enum`, stored just as enum index of `i32` type) 44 | * [x] newtype struct (aka `struct Io(u32)`, stored as underlaying value) 45 | * [-] newtype variant 46 | * [x] seq, like vector (stored as array) 47 | * [x] tuple (stored as array) 48 | * [x] tuple struct (stored as array) 49 | * [-] tuple variant 50 | * [x] map (stored as map) 51 | * [x] struct (stored as map) 52 | * [-] struct variant 53 | 54 | See the [Serde data model](https://serde.rs/data-model.html) for reference. 55 | 56 | # Examples 57 | 58 | ```rust 59 | extern crate sciter; 60 | extern crate sciter_serde; 61 | 62 | use sciter::Value; 63 | use sciter_serde::{from_value, to_value}; 64 | 65 | fn back_and_forth() { 66 | let v: Value = to_value(&true).unwrap(); 67 | let b: bool = from_value(&v).unwrap(); 68 | assert_eq!(b, true); 69 | } 70 | 71 | fn main() { 72 | 73 | // bool 74 | let v: Value = to_value(&true).unwrap(); 75 | assert!(v.is_bool()); 76 | assert_eq!(v, Value::from(true)); 77 | 78 | // numbers 79 | let v = to_value(&12u32).unwrap(); 80 | assert_eq!(v, 12.into()); 81 | 82 | let v = to_value(& 42.0f64).unwrap(); 83 | assert_eq!(v, 42.0f64.into()); 84 | 85 | // strings 86 | let v = to_value("hello").unwrap(); 87 | assert_eq!(v, "hello".into()); 88 | 89 | // arrays 90 | let a = [1,2,3]; 91 | let v = to_value(&a).unwrap(); 92 | assert_eq!(v, a.iter().cloned().collect()); 93 | 94 | // maps 95 | let m = { 96 | use std::collections::BTreeMap; 97 | let mut m = BTreeMap::new(); 98 | m.insert("17", 17); 99 | m.insert("42", 42); 100 | m 101 | }; 102 | let v = to_value(&m).unwrap(); 103 | assert_eq!(v, Value::parse(r#"{ "17": 17, "42": 42 }"#).unwrap()); 104 | } 105 | ``` 106 | 107 | With derived serialization: 108 | 109 | ```rust 110 | # #![doc(test(no_crate_inject))] 111 | #[macro_use] 112 | extern crate serde_derive; 113 | extern crate serde; 114 | 115 | extern crate sciter; 116 | extern crate sciter_serde; 117 | 118 | use sciter::Value; 119 | use sciter_serde::to_value; 120 | 121 | fn main() { 122 | 123 | // structs 124 | #[derive(Serialize)] 125 | struct Test { 126 | x: i32, 127 | y: i32, 128 | } 129 | 130 | let v = to_value(&Test {x: 1, y: 2}).unwrap(); 131 | assert_eq!(v, Value::parse(r#"{ "x": 1, "y": 2 }"#).unwrap()); 132 | } 133 | 134 | ``` 135 | 136 | */ 137 | #![allow(clippy::redundant_field_names)] 138 | #![allow(clippy::tabs_in_doc_comments)] 139 | 140 | #[macro_use] 141 | extern crate serde; 142 | extern crate sciter; 143 | 144 | 145 | mod error; 146 | mod ser; 147 | mod de; 148 | 149 | #[doc(inline)] 150 | pub use ser::to_value; 151 | 152 | #[doc(inline)] 153 | pub use de::from_value; 154 | 155 | pub use error::{Result, Error}; 156 | -------------------------------------------------------------------------------- /examples/video.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | Video behavior demo 4 | 19 | 81 | 82 | 103 | 104 | 105 | 106 | 107 |

This demo simulates partial video frame update. 108 | On each frame (24 FPS) it updates another portion of the frame.

109 | 110 |
111 | 112 | 113 |
114 | 115 |
116 |
frame size: x 117 |
118 | 119 |