Skip to content

Commit 2c4741c

Browse files
authored
Support transparency; many other features (#11)
* Add transparency/devtools flags Transparency is disabled by default because on osx it requires private APIs. That unfortunately means that an app with transparency *can't* be published to the app store. Devtools are enabled in all debug builds but are disabled in release builds. Again, on OSX it uses private APIs so an app w/ devtools enabled can't be published to the app store. * Use transparent flag in build * Features out the wazoo
1 parent 95670dd commit 2c4741c

File tree

6 files changed

+136
-10
lines changed

6 files changed

+136
-10
lines changed

Cargo.toml

+13
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,16 @@ serde_json = "1"
99
tao = "0.28.0"
1010
wry = "0.39.5"
1111
schemars = "0.8.21"
12+
13+
[features]
14+
transparent = ["wry/transparent"]
15+
devtools = ["wry/devtools"]
16+
17+
[target.'cfg(any(feature = "transparent", feature = "devtools"))'.dependencies]
18+
wry = { version = "0.39.5", features = [] }
19+
20+
[target.'cfg(feature = "transparent")'.dependencies.wry]
21+
features = ["transparent"]
22+
23+
[target.'cfg(feature = "devtools")'.dependencies.wry]
24+
features = ["devtools"]

deno.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"tasks": {
77
"dev": "deno run --watch main.ts",
88
"gen": "cargo test && deno run -A scripts/generate-zod.ts",
9-
"build": "deno task gen && cargo build",
9+
"build": "deno task gen && cargo build -F transparent",
1010
"example:simple": "deno run -A examples/simple.ts"
1111
}
1212
}

schemas/WebViewOptions.json

+44
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/generate-zod.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import { walk } from "https://deno.land/std@0.190.0/fs/walk.ts";
22
import { basename } from "https://deno.land/std@0.190.0/path/mod.ts";
33
import { match, P } from "npm:ts-pattern";
4-
import {
5-
type JSONSchema7 as JSONSchema,
6-
JSONSchema7Definition,
4+
import type {
5+
JSONSchema7 as JSONSchema,
6+
JSONSchema7Definition as JSONSchemaDefinition,
77
} from "npm:@types/json-schema";
88

99
const schemasDir = new URL("../schemas", import.meta.url).pathname;
1010
const outputFile = new URL("../src/schemas.ts", import.meta.url).pathname;
1111

12-
const isDescriminatedUnion = (def: JSONSchema7Definition[] | undefined) => {
12+
const isDescriminatedUnion = (def: JSONSchemaDefinition[] | undefined) => {
1313
return def && typeof def[0] === "object" &&
1414
def[0]?.required?.includes("$type");
1515
};
@@ -22,6 +22,13 @@ function generateZodSchema(schema: JSONSchema) {
2222
const wn = (...t: string[]) => w(...t, "\n");
2323

2424
match(schema)
25+
.with(
26+
{ type: "boolean" },
27+
(schema) =>
28+
w(
29+
"z.boolean()" + (schema.default ? `.optional()` : ""),
30+
),
31+
)
2532
.with({ type: "string", enum: P.array() }, (schema) => {
2633
w(`z.literal("${schema.enum[0]}")`);
2734
})
@@ -30,6 +37,7 @@ function generateZodSchema(schema: JSONSchema) {
3037
w("z");
3138
for (const type of schema.type) {
3239
match(type)
40+
.with("boolean", () => w(".boolean()"))
3341
.with("string", () => w(".string()"))
3442
.with("null", () => w(".nullable()"))
3543
.otherwise(() => {

src/main.rs

+57-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,55 @@
1+
use std::borrow::{Borrow, BorrowMut};
12
use std::env;
23
use std::io::{self, BufRead, Write};
34
use std::sync::mpsc;
45

56
use schemars::JsonSchema;
67
use serde::{Deserialize, Serialize};
78
use serde_json;
9+
use tao::window::Fullscreen;
810

911
#[derive(JsonSchema, Deserialize, Debug)]
1012
struct WebViewOptions {
1113
title: String,
1214
#[serde(flatten)]
1315
target: WebViewTarget,
16+
/// Sets whether the window should be fullscreen.
17+
#[serde(default)]
18+
fullscreen: bool,
19+
/// Sets whether the window should have a border, a title bar, etc.
20+
#[serde(default = "default_true")]
21+
decorations: bool,
22+
#[serde(default)]
23+
transparent: bool,
24+
/// Sets whether all media can be played without user interaction.
25+
#[serde(default)]
26+
autoplay: bool,
27+
/// Enable or disable web inspector which is usually called devtools.
28+
///
29+
/// Note this only enables devtools to the webview. To open it, you can call WebView::open_devtools, or right click the page and open it from the context menu.
30+
#[serde(default)]
31+
devtools: bool,
32+
/// Run the WebView with incognito mode. Note that WebContext will be ingored if incognito is enabled.
33+
///
34+
/// Platform-specific:
35+
/// - Windows: Requires WebView2 Runtime version 101.0.1210.39 or higher, does nothing on older versions, see https://learn.microsoft.com/en-us/microsoft-edge/webview2/release-notes/archive?tabs=dotnetcsharp#10121039
36+
#[serde(default)]
37+
incognito: bool,
38+
/// Enables clipboard access for the page rendered on Linux and Windows.
39+
///
40+
/// macOS doesn’t provide such method and is always enabled by default. But your app will still need to add menu item accelerators to use the clipboard shortcuts.
41+
#[serde(default)]
42+
clipboard: bool,
43+
/// Sets whether the webview should be focused when created. Default is false.
44+
#[serde(default)]
45+
focused: bool,
46+
/// Sets whether clicking an inactive window also clicks through to the webview. Default is false.
47+
#[serde(default)]
48+
accept_first_mouse: bool,
49+
}
50+
51+
fn default_true() -> bool {
52+
true
1453
}
1554

1655
#[derive(JsonSchema, Deserialize, Debug)]
@@ -57,16 +96,29 @@ fn main() -> wry::Result<()> {
5796
use wry::WebViewBuilder;
5897

5998
let event_loop = EventLoop::new();
60-
let window = WindowBuilder::new()
99+
let mut window_builder = WindowBuilder::new()
61100
.with_title(webview_options.title)
62-
.build(&event_loop)
63-
.unwrap();
101+
.with_transparent(webview_options.transparent)
102+
.with_decorations(webview_options.decorations);
103+
if webview_options.fullscreen {
104+
window_builder = window_builder.with_fullscreen(Some(Fullscreen::Borderless(None)));
105+
}
106+
let window = window_builder.build(&event_loop).unwrap();
107+
108+
eprintln!("transparent: {:?}", webview_options.transparent);
64109

65-
let webview = match webview_options.target {
110+
let webview_builder = match webview_options.target {
66111
WebViewTarget::Url(url) => WebViewBuilder::new(&window).with_url(url),
67112
WebViewTarget::Html(html) => WebViewBuilder::new(&window).with_html(html),
68113
}
69-
.build()?;
114+
.with_transparent(webview_options.transparent)
115+
.with_autoplay(webview_options.autoplay)
116+
.with_incognito(webview_options.incognito)
117+
.with_clipboard(webview_options.clipboard)
118+
.with_focused(webview_options.focused)
119+
.with_devtools(webview_options.devtools)
120+
.with_accept_first_mouse(webview_options.accept_first_mouse);
121+
let webview = webview_builder.build()?;
70122

71123
let (tx, to_deno) = mpsc::channel::<WebViewEvent>();
72124
let (from_deno, rx) = mpsc::channel::<ClientEvent>();

src/schemas.ts

+9
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,16 @@ export type ClientEvent = z.infer<typeof ClientEvent>;
1515

1616
export const WebViewOptions = z.intersection(
1717
z.object({
18+
accept_first_mouse: z.boolean().optional(),
19+
autoplay: z.boolean().optional(),
20+
clipboard: z.boolean().optional(),
21+
decorations: z.boolean().optional().optional(),
22+
devtools: z.boolean().optional(),
23+
focused: z.boolean().optional(),
24+
fullscreen: z.boolean().optional(),
25+
incognito: z.boolean().optional(),
1826
title: z.string(),
27+
transparent: z.boolean().optional(),
1928
}),
2029
z.union([
2130
z.object({

0 commit comments

Comments
 (0)