diff --git a/Cargo.lock b/Cargo.lock index d6ca6fd..30db59b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,12 +28,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -[[package]] -name = "boxfnonce" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5988cb1d626264ac94100be357308f29ff7cbdd3b36bda27f450a4ee3f713426" - [[package]] name = "cargo_gn" version = "0.0.15" @@ -73,10 +67,9 @@ name = "deno_webview" version = "0.1.0" dependencies = [ "deno_core", - "futures 0.3.4", "serde", "serde_json", - "web-view", + "webview-sys", ] [[package]] @@ -429,23 +422,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "urlencoding" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3df3561629a8bb4c57e5a2e4c43348d9e29c7c29d9b1c4c1f47166deca8f37ed" - -[[package]] -name = "web-view" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2072c76e359687194782398a2886de992cb34ea587b6b7dc68c9d1113adaf4bc" -dependencies = [ - "boxfnonce", - "urlencoding", - "webview-sys", -] - [[package]] name = "webview-sys" version = "0.4.0" @@ -459,9 +435,9 @@ dependencies = [ [[package]] name = "which" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5475d47078209a02e60614f7ba5e645ef3ed60f771920ac1906d7c1cc65024c8" +checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" dependencies = [ "failure", "libc", diff --git a/Cargo.toml b/Cargo.toml index 6d572d9..2358fcc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,8 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -futures = "0.3.4" deno_core = "0.35.0" -web-view = "0.6.0" +webview-sys = "0.4.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/README.md b/README.md index 9dff3aa..b2f3e70 100644 --- a/README.md +++ b/README.md @@ -12,5 +12,7 @@ the basics are really implemented yet (apart from opening a webview window). - [ ] Two-way deno bindings (to call deno from javascript) - [ ] Multiple windows? - [ ] Easier importing of scripts, images and css +- [ ] Dialog +- [ ] DialogBuilder and WebViewBuilder - [ ] Examples - [ ] Tests diff --git a/mod.ts b/mod.ts index a7702f0..bfb1bcc 100644 --- a/mod.ts +++ b/mod.ts @@ -1,28 +1,49 @@ import { prepare } from "https://deno.land/x/plugin_prepare/mod.ts"; -export interface Options { +const releaseUrl = + "https://github.com/eliassjogreen/deno_webview/releases/download/0.0.1"; + +const plugin = await prepare({ + name: "deno_webview", + urls: { + mac: `${releaseUrl}/libdeno_webview.dylib`, + win: `${releaseUrl}/deno_webview.dll`, + linux: `${releaseUrl}/libdeno_webview.so` + } +}); + +interface NewArgs { title: string; + url: string; width: number; height: number; resizable: boolean; debug: boolean; - content: string; } -export async function run(options: Options) { - const releaseUrl = - "https://github.com/eliassjogreen/deno_webview/releases/download/0.0.1"; +interface EvalArgs { + js: string; +} - const deno_webview: Deno.Plugin = await prepare({ - name: "deno_webview", - urls: { - mac: `${releaseUrl}/libdeno_webview.dylib`, - win: `${releaseUrl}/deno_webview.dll`, - linux: `${releaseUrl}/libdeno_webview.so` - } - }); +interface InjectCssArgs { + css: string; +} - const { webview_run } = deno_webview.ops; +interface SetColorArgs { + r: number; + g: number; + b: number; + a: number; +} + +interface SetTitleArgs { + title: String; +} + +interface SetFullscreenArgs { + fullscreen: boolean; +} - webview_run.dispatch(new TextEncoder().encode(JSON.stringify(options))); +interface LoopArgs { + blocking: number; } diff --git a/src/lib.rs b/src/lib.rs index 7d5cd56..f07dcc2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,50 +1,199 @@ -#[macro_use] -extern crate deno_core; -extern crate futures; -extern crate serde; -extern crate serde_json; - -use deno_core::CoreOp; -use deno_core::Op; -use deno_core::PluginInitContext; -use deno_core::ZeroCopyBuf; -use serde::{Deserialize, Serialize}; -use web_view::*; - -#[derive(Serialize, Deserialize)] -struct Options { - title: String, - width: i32, - height: i32, - resizable: bool, - debug: bool, - content: String, -} - -fn init(context: &mut dyn PluginInitContext) { - context.register_op("webview_run", Box::new(op_webview_run)); -} -init_fn!(init); - -pub fn op_webview_run(data: &[u8], zero_copy: Option) -> CoreOp { - webview_run(std::str::from_utf8(data).unwrap()).unwrap(); - - Op::Sync(Box::new([0])) -} - -fn webview_run<'a>(data: &'a str) -> Result<(), serde_json::Error> { - let options: Options = serde_json::from_str(data)?; - - let webview = web_view::builder() - .title(&options.title) - .content(Content::Html(options.content)) - .size(options.width, options.height) - .resizable(options.resizable) - .debug(options.debug) - .user_data(()) - .invoke_handler(|_webview, _arg| Ok(())) - .build() - .unwrap(); - webview.run().unwrap(); - Ok(()) -} +#[macro_use] +extern crate deno_core; +extern crate serde; +extern crate serde_json; +extern crate webview_sys; + +use deno_core::{CoreOp, Op, PluginInitContext, ZeroCopyBuf}; +use serde::{Deserialize, Serialize}; +use std::{ffi::CString, ptr::null_mut}; +use webview_sys::*; + +#[derive(Serialize, Deserialize)] +struct NewArgs { + title: String, + url: String, + width: i32, + height: i32, + resizable: bool, + debug: bool, +} + +#[derive(Serialize, Deserialize)] +struct EvalArgs { + js: String, +} + +#[derive(Serialize, Deserialize)] +struct InjectCssArgs { + css: String, +} + +#[derive(Serialize, Deserialize)] +struct SetColorArgs { + r: u8, + g: u8, + b: u8, + a: u8, +} + +#[derive(Serialize, Deserialize)] +struct SetTitleArgs { + title: String, +} + +#[derive(Serialize, Deserialize)] +struct SetFullscreenArgs { + fullscreen: bool, +} + +#[derive(Serialize, Deserialize)] +struct LoopArgs { + blocking: i32, +} + +static mut CWEBVIEW: Option<*mut CWebView> = None; + +fn init(context: &mut dyn PluginInitContext) { + context.register_op("webview_new", Box::new(op_webview_new)); + context.register_op("webview_exit", Box::new(op_webview_exit)); + context.register_op("webview_eval", Box::new(op_webview_eval)); + context.register_op("webview_inject_css", Box::new(op_webview_inject_css)); + context.register_op("webview_set_color", Box::new(op_webview_set_color)); + context.register_op("webview_set_title", Box::new(op_webview_set_title)); + context.register_op( + "webview_set_fullscreen", + Box::new(op_webview_set_fullscreen), + ); + context.register_op("webview_loop", Box::new(op_webview_loop)); +} +init_fn!(init); + +fn op_webview_new(data: &[u8], _zero_copy: Option) -> CoreOp { + unsafe { + if CWEBVIEW.is_some() { + return Op::Sync(Box::new([false as u8])); + } + + let args: NewArgs = serde_json::from_slice(data).unwrap(); + + let title = CString::new(args.title).unwrap(); + let url = CString::new(args.url).unwrap(); + let width = args.width; + let height = args.height; + let resizable = args.resizable as i32; + let debug = args.debug as i32; + + CWEBVIEW = Some(webview_new( + title.as_ptr(), + url.as_ptr(), + width, + height, + resizable, + debug, + None, + null_mut(), + )); + + Op::Sync(Box::new([true as u8])) + } +} + +fn op_webview_exit(_data: &[u8], _zero_copy: Option) -> CoreOp { + unsafe { + if CWEBVIEW.is_none() { + return Op::Sync(Box::new([false as u8])); + } + + webview_exit(CWEBVIEW.unwrap()); + + Op::Sync(Box::new([true as u8])) + } +} + +fn op_webview_eval(data: &[u8], _zero_copy: Option) -> CoreOp { + unsafe { + if CWEBVIEW.is_none() { + return Op::Sync(Box::new([false as u8])); + } + + let args: EvalArgs = serde_json::from_slice(data).unwrap(); + let js = CString::new(args.js).unwrap(); + + webview_eval(CWEBVIEW.unwrap(), js.as_ptr()); + + Op::Sync(Box::new([true as u8])) + } +} + +fn op_webview_inject_css(data: &[u8], _zero_copy: Option) -> CoreOp { + unsafe { + if CWEBVIEW.is_none() { + return Op::Sync(Box::new([false as u8])); + } + + let args: InjectCssArgs = serde_json::from_slice(data).unwrap(); + let css = CString::new(args.css).unwrap(); + + webview_inject_css(CWEBVIEW.unwrap(), css.as_ptr()); + + Op::Sync(Box::new([true as u8])) + } +} + +fn op_webview_set_color(data: &[u8], _zero_copy: Option) -> CoreOp { + unsafe { + if CWEBVIEW.is_none() { + return Op::Sync(Box::new([false as u8])); + } + + let args: SetColorArgs = serde_json::from_slice(data).unwrap(); + + webview_set_color(CWEBVIEW.unwrap(), args.r, args.g, args.b, args.a); + + Op::Sync(Box::new([true as u8])) + } +} + +fn op_webview_set_title(data: &[u8], _zero_copy: Option) -> CoreOp { + unsafe { + if CWEBVIEW.is_none() { + return Op::Sync(Box::new([false as u8])); + } + + let args: SetTitleArgs = serde_json::from_slice(data).unwrap(); + let title = CString::new(args.title).unwrap(); + + webview_set_title(CWEBVIEW.unwrap(), title.as_ptr()); + + Op::Sync(Box::new([true as u8])) + } +} + +fn op_webview_set_fullscreen(data: &[u8], _zero_copy: Option) -> CoreOp { + unsafe { + if CWEBVIEW.is_none() { + return Op::Sync(Box::new([false as u8])); + } + + let args: SetFullscreenArgs = serde_json::from_slice(data).unwrap(); + let fullscreen = args.fullscreen as i32; + + webview_set_fullscreen(CWEBVIEW.unwrap(), fullscreen); + + Op::Sync(Box::new([true as u8])) + } +} + +fn op_webview_loop(data: &[u8], _zero_copy: Option) -> CoreOp { + unsafe { + if CWEBVIEW.is_none() { + return Op::Sync(Box::new([false as u8])); + } + + let args: LoopArgs = serde_json::from_slice(data).unwrap(); + let result = webview_loop(CWEBVIEW.unwrap(), args.blocking); + + Op::Sync(Box::new(result.to_be_bytes())) + } +} diff --git a/test.ts b/test.ts index cedc4e9..24b8567 100644 --- a/test.ts +++ b/test.ts @@ -1,10 +1 @@ -import { run } from "./mod.ts"; - -await run({ - title: "Hello World!", - width: 300, - height: 400, - resizable: false, - debug: true, - content: `Hello from deno` -}); +// TODO