Re-introduce Web examples (#3637)

This commit is contained in:
daxpedda 2024-04-18 19:43:39 +02:00 committed by GitHub
parent 24faacf497
commit c15fa6e433
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 259 additions and 121 deletions

View File

@ -1,6 +1,3 @@
[alias]
run-wasm = ["run", "--release", "--package", "run-wasm", "--"]
# Allow rust-analyzer and local `cargo doc` invocations to pick up unreleased changelog entries
#
# Note that these flags are (intentionally) not included when building from the downloaded crate.

View File

@ -1,7 +1,10 @@
[package]
name = "winit"
version = "0.29.15"
authors = ["The winit contributors", "Pierre Krieger <pierre.krieger1708@gmail.com>"]
authors = [
"The winit contributors",
"Pierre Krieger <pierre.krieger1708@gmail.com>",
]
description = "Cross-platform window creation library."
keywords = ["windowing"]
readme = "README.md"
@ -45,7 +48,15 @@ rustdoc-args = ["--cfg", "docsrs"]
[features]
default = ["rwh_06", "x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"]
x11 = ["x11-dl", "bytemuck", "percent-encoding", "xkbcommon-dl/x11", "x11rb"]
wayland = ["wayland-client", "wayland-backend", "wayland-protocols", "wayland-protocols-plasma", "sctk", "ahash", "memmap2"]
wayland = [
"wayland-client",
"wayland-backend",
"wayland-protocols",
"wayland-protocols-plasma",
"sctk",
"ahash",
"memmap2",
]
wayland-dlopen = ["wayland-backend/dlopen"]
wayland-csd-adwaita = ["sctk-adwaita", "sctk-adwaita/ab_glyph"]
wayland-csd-adwaita-crossfont = ["sctk-adwaita", "sctk-adwaita/crossfont"]
@ -66,8 +77,12 @@ bitflags = "2"
cursor-icon = "1.1.0"
dpi = { version = "0.1.1", path = "dpi" }
rwh_04 = { package = "raw-window-handle", version = "0.4", optional = true }
rwh_05 = { package = "raw-window-handle", version = "0.5.2", features = ["std"], optional = true }
rwh_06 = { package = "raw-window-handle", version = "0.6", features = ["std"], optional = true }
rwh_05 = { package = "raw-window-handle", version = "0.5.2", features = [
"std",
], optional = true }
rwh_06 = { package = "raw-window-handle", version = "0.6", features = [
"std",
], optional = true }
serde = { workspace = true, optional = true }
smol_str = "0.2.0"
tracing = { version = "0.1.40", default_features = false }
@ -79,7 +94,12 @@ tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
winit = { path = ".", features = ["rwh_05"] }
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dev-dependencies]
softbuffer = { version = "0.3.0", default-features = false, features = ["x11", "x11-dlopen", "wayland", "wayland-dlopen"] }
softbuffer = { version = "0.3.0", default-features = false, features = [
"x11",
"x11-dlopen",
"wayland",
"wayland-dlopen",
] }
[target.'cfg(target_os = "android")'.dependencies]
android-activity = "0.5.0"
@ -194,15 +214,35 @@ calloop = "0.12.3"
libc = "0.2.64"
memmap2 = { version = "0.9.0", optional = true }
percent-encoding = { version = "2.0", optional = true }
rustix = { version = "0.38.4", default-features = false, features = ["std", "system", "thread", "process"] }
sctk = { package = "smithay-client-toolkit", version = "0.18.0", default-features = false, features = ["calloop"], optional = true }
rustix = { version = "0.38.4", default-features = false, features = [
"std",
"system",
"thread",
"process",
] }
sctk = { package = "smithay-client-toolkit", version = "0.18.0", default-features = false, features = [
"calloop",
], optional = true }
sctk-adwaita = { version = "0.9.0", default_features = false, optional = true }
wayland-backend = { version = "0.3.0", default_features = false, features = ["client_system"], optional = true }
wayland-backend = { version = "0.3.0", default_features = false, features = [
"client_system",
], optional = true }
wayland-client = { version = "0.31.1", optional = true }
wayland-protocols = { version = "0.31.0", features = [ "staging"], optional = true }
wayland-protocols-plasma = { version = "0.2.0", features = [ "client" ], optional = true }
wayland-protocols = { version = "0.31.0", features = [
"staging",
], optional = true }
wayland-protocols-plasma = { version = "0.2.0", features = [
"client",
], optional = true }
x11-dl = { version = "2.19.1", optional = true }
x11rb = { version = "0.13.0", default-features = false, features = ["allow-unsafe-code", "dl-libxcb", "randr", "resource_manager", "xinput", "xkb"], optional = true }
x11rb = { version = "0.13.0", default-features = false, features = [
"allow-unsafe-code",
"dl-libxcb",
"randr",
"resource_manager",
"xinput",
"xkb",
], optional = true }
xkbcommon-dl = "0.4.2"
[target.'cfg(target_os = "redox")'.dependencies]
@ -266,8 +306,8 @@ atomic-waker = "1"
concurrent-queue = { version = "2", default-features = false }
[target.'cfg(target_family = "wasm")'.dev-dependencies]
console_log = "1"
web-sys = { version = "0.3.22", features = ['CanvasRenderingContext2d'] }
console_error_panic_hook = "0.1"
tracing-web = "0.1"
[[example]]
doc-scrape-examples = true
@ -275,10 +315,7 @@ name = "window"
[workspace]
resolver = "2"
members = [
"dpi",
"run-wasm",
]
members = ["dpi"]
[workspace.package]
rust-version = "1.70.0"

View File

@ -4,6 +4,7 @@ use std::thread;
#[cfg(not(web_platform))]
use std::time;
use ::tracing::{info, warn};
#[cfg(web_platform)]
use web_time as time;
@ -15,6 +16,8 @@ use winit::window::{Window, WindowId};
#[path = "util/fill.rs"]
mod fill;
#[path = "util/tracing.rs"]
mod tracing;
const WAIT_TIME: time::Duration = time::Duration::from_millis(100);
const POLL_SLEEP_TIME: time::Duration = time::Duration::from_millis(100);
@ -28,13 +31,16 @@ enum Mode {
}
fn main() -> Result<(), impl std::error::Error> {
tracing_subscriber::fmt::init();
#[cfg(web_platform)]
console_error_panic_hook::set_once();
println!("Press '1' to switch to Wait mode.");
println!("Press '2' to switch to WaitUntil mode.");
println!("Press '3' to switch to Poll mode.");
println!("Press 'R' to toggle request_redraw() calls.");
println!("Press 'Esc' to close the window.");
tracing::init();
info!("Press '1' to switch to Wait mode.");
info!("Press '2' to switch to WaitUntil mode.");
info!("Press '3' to switch to Poll mode.");
info!("Press 'R' to toggle request_redraw() calls.");
info!("Press 'Esc' to close the window.");
let event_loop = EventLoop::new().unwrap();
@ -53,7 +59,7 @@ struct ControlFlowDemo {
impl ApplicationHandler for ControlFlowDemo {
fn new_events(&mut self, _event_loop: &ActiveEventLoop, cause: StartCause) {
println!("new_events: {cause:?}");
info!("new_events: {cause:?}");
self.wait_cancelled = match cause {
StartCause::WaitCancelled { .. } => self.mode == Mode::WaitUntil,
@ -74,7 +80,7 @@ impl ApplicationHandler for ControlFlowDemo {
_window_id: WindowId,
event: WindowEvent,
) {
println!("{event:?}");
info!("{event:?}");
match event {
WindowEvent::CloseRequested => {
@ -93,19 +99,19 @@ impl ApplicationHandler for ControlFlowDemo {
// See the `key_binding` example
Key::Character("1") => {
self.mode = Mode::Wait;
println!("\nmode: {:?}\n", self.mode);
warn!("mode: {:?}", self.mode);
}
Key::Character("2") => {
self.mode = Mode::WaitUntil;
println!("\nmode: {:?}\n", self.mode);
warn!("mode: {:?}", self.mode);
}
Key::Character("3") => {
self.mode = Mode::Poll;
println!("\nmode: {:?}\n", self.mode);
warn!("mode: {:?}", self.mode);
}
Key::Character("r") => {
self.request_redraw = !self.request_redraw;
println!("\nrequest_redraw: {}\n", self.request_redraw);
warn!("request_redraw: {}", self.request_redraw);
}
Key::Named(NamedKey::Escape) => {
self.close_requested = true;

27
examples/util/tracing.rs Normal file
View File

@ -0,0 +1,27 @@
#[cfg(not(web_platform))]
pub fn init() {
use tracing_subscriber::filter::{EnvFilter, LevelFilter};
tracing_subscriber::fmt()
.with_env_filter(
EnvFilter::builder()
.with_default_directive(LevelFilter::INFO.into())
.from_env_lossy(),
)
.init();
}
#[cfg(web_platform)]
pub fn init() {
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
tracing_subscriber::registry()
.with(
tracing_subscriber::fmt::layer()
.with_ansi(false)
.without_time()
.with_writer(tracing_web::MakeWebConsoleWriter::new()),
)
.init();
}

View File

@ -7,8 +7,8 @@ use std::fmt::Debug;
use std::mem;
#[cfg(not(any(android_platform, ios_platform)))]
use std::num::NonZeroU32;
use std::path::Path;
use ::tracing::{error, info};
use cursor_icon::CursorIcon;
#[cfg(not(any(android_platform, ios_platform)))]
use rwh_05::HasRawDisplayHandle;
@ -34,10 +34,18 @@ use winit::platform::startup_notify::{
self, EventLoopExtStartupNotify, WindowAttributesExtStartupNotify, WindowExtStartupNotify,
};
#[path = "util/tracing.rs"]
mod tracing;
/// The amount of points to around the window for drag resize direction calculations.
const BORDER_SIZE: f64 = 20.;
fn main() -> Result<(), Box<dyn Error>> {
#[cfg(web_platform)]
console_error_panic_hook::set_once();
tracing::init();
let event_loop = EventLoop::<UserEvent>::with_user_event().build()?;
let _event_loop_proxy = event_loop.create_proxy();
@ -46,7 +54,7 @@ fn main() -> Result<(), Box<dyn Error>> {
std::thread::spawn(move || {
// Wake up the `event_loop` once every second and dispatch a custom event
// from a different thread.
println!("Starting to send user event every second");
info!("Starting to send user event every second");
loop {
let _ = _event_loop_proxy.send_event(UserEvent::WakeUp);
std::thread::sleep(std::time::Duration::from_secs(1));
@ -88,11 +96,9 @@ impl Application {
// by WM, and on Windows, you still have to account for screen scaling. Here we use 32px,
// since it seems to work well enough in most cases. Be careful about going too high, or
// you'll be bitten by the low-quality downscaling built into the WM.
let path = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/data/icon.png");
let icon = load_icon(include_bytes!("data/icon.png"));
let icon = load_icon(Path::new(path));
println!("Loading cursor assets");
info!("Loading cursor assets");
let custom_cursors = vec![
event_loop.create_custom_cursor(decode_cursor(include_bytes!("data/cross.png"))),
event_loop.create_custom_cursor(decode_cursor(include_bytes!("data/cross2.png"))),
@ -124,7 +130,7 @@ impl Application {
#[cfg(any(x11_platform, wayland_platform))]
if let Some(token) = event_loop.read_token_from_env() {
startup_notify::reset_activation_token_env();
println!("Using token {:?} to activate a window", token);
info!("Using token {:?} to activate a window", token);
window_attributes = window_attributes.with_activation_token(token);
}
@ -133,6 +139,12 @@ impl Application {
window_attributes = window_attributes.with_tabbing_identifier(&tab_id);
}
#[cfg(web_platform)]
{
use winit::platform::web::WindowAttributesExtWebSys;
window_attributes = window_attributes.with_append(true);
}
let window = event_loop.create_window(window_attributes)?;
#[cfg(ios_platform)]
@ -145,7 +157,7 @@ impl Application {
let window_state = WindowState::new(self, window)?;
let window_id = window_state.window.id();
println!("Created new window with id={window_id:?}");
info!("Created new window with id={window_id:?}");
self.windows.insert(window_id, window_state);
Ok(window_id)
}
@ -153,7 +165,7 @@ impl Application {
fn handle_action(&mut self, event_loop: &ActiveEventLoop, window_id: WindowId, action: Action) {
// let cursor_position = self.cursor_position;
let window = self.windows.get_mut(&window_id).unwrap();
println!("Executing action: {action:?}");
info!("Executing action: {action:?}");
match action {
Action::CloseWindow => {
let _ = self.windows.remove(&window_id);
@ -161,13 +173,13 @@ impl Application {
Action::CreateNewWindow => {
#[cfg(any(x11_platform, wayland_platform))]
if let Err(err) = window.window.request_activation_token() {
println!("Failed to get activation token: {err}");
info!("Failed to get activation token: {err}");
} else {
return;
}
if let Err(err) = self.create_window(event_loop, None) {
eprintln!("Error creating new window: {err}");
error!("Error creating new window: {err}");
}
}
Action::ToggleResizeIncrements => window.toggle_resize_increments(),
@ -180,6 +192,12 @@ impl Application {
Action::Minimize => window.minimize(),
Action::NextCursor => window.next_cursor(),
Action::NextCustomCursor => window.next_custom_cursor(&self.custom_cursors),
#[cfg(web_platform)]
Action::UrlCustomCursor => window.url_custom_cursor(event_loop),
#[cfg(web_platform)]
Action::AnimationCustomCursor => {
window.animation_custom_cursor(event_loop, &self.custom_cursors)
}
Action::CycleCursorGrab => window.cycle_cursor_grab(),
Action::DragWindow => window.drag_window(),
Action::DragResizeWindow => window.drag_resize_window(),
@ -191,7 +209,7 @@ impl Application {
Action::CreateNewTab => {
let tab_id = window.window.tabbing_identifier();
if let Err(err) = self.create_window(event_loop, Some(tab_id)) {
eprintln!("Error creating new window: {err}");
error!("Error creating new window: {err}");
}
}
Action::RequestResize => window.swap_dimensions(),
@ -199,7 +217,7 @@ impl Application {
}
fn dump_monitors(&self, event_loop: &ActiveEventLoop) {
println!("Monitors information");
info!("Monitors information");
let primary_monitor = event_loop.primary_monitor();
for monitor in event_loop.available_monitors() {
let intro = if primary_monitor.as_ref() == Some(&monitor) {
@ -209,30 +227,32 @@ impl Application {
};
if let Some(name) = monitor.name() {
println!("{intro}: {name}");
info!("{intro}: {name}");
} else {
println!("{intro}: [no name]");
info!("{intro}: [no name]");
}
let PhysicalSize { width, height } = monitor.size();
print!(" Current mode: {width}x{height}");
if let Some(m_hz) = monitor.refresh_rate_millihertz() {
println!(" @ {}.{} Hz", m_hz / 1000, m_hz % 1000);
} else {
println!();
}
info!(
" Current mode: {width}x{height}{}",
if let Some(m_hz) = monitor.refresh_rate_millihertz() {
format!(" @ {}.{} Hz", m_hz / 1000, m_hz % 1000)
} else {
String::new()
}
);
let PhysicalPosition { x, y } = monitor.position();
println!(" Position: {x},{y}");
info!(" Position: {x},{y}");
println!(" Scale factor: {}", monitor.scale_factor());
info!(" Scale factor: {}", monitor.scale_factor());
println!(" Available modes (width x height x bit-depth):");
info!(" Available modes (width x height x bit-depth):");
for mode in monitor.video_modes() {
let PhysicalSize { width, height } = mode.size();
let bits = mode.bit_depth();
let m_hz = mode.refresh_rate_millihertz();
println!(
info!(
" {width}x{height}x{bits} @ {}.{} Hz",
m_hz / 1000,
m_hz % 1000
@ -260,9 +280,9 @@ impl Application {
}
fn print_help(&self) {
println!("Keyboard bindings:");
info!("Keyboard bindings:");
for binding in KEY_BINDINGS {
println!(
info!(
"{}{:<10} - {} ({})",
modifiers_to_string(binding.mods),
binding.trigger,
@ -270,9 +290,9 @@ impl Application {
binding.action.help(),
);
}
println!("Mouse bindings:");
info!("Mouse bindings:");
for binding in MOUSE_BINDINGS {
println!(
info!(
"{}{:<10} - {} ({})",
modifiers_to_string(binding.mods),
mouse_button_to_string(binding.trigger),
@ -285,7 +305,7 @@ impl Application {
impl ApplicationHandler<UserEvent> for Application {
fn user_event(&mut self, _event_loop: &ActiveEventLoop, event: UserEvent) {
println!("User event: {event:?}");
info!("User event: {event:?}");
}
fn window_event(
@ -305,40 +325,40 @@ impl ApplicationHandler<UserEvent> for Application {
}
WindowEvent::Focused(focused) => {
if focused {
println!("Window={window_id:?} focused");
info!("Window={window_id:?} focused");
} else {
println!("Window={window_id:?} unfocused");
info!("Window={window_id:?} unfocused");
}
}
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
println!("Window={window_id:?} changed scale to {scale_factor}");
info!("Window={window_id:?} changed scale to {scale_factor}");
}
WindowEvent::ThemeChanged(theme) => {
println!("Theme changed to {theme:?}");
info!("Theme changed to {theme:?}");
window.set_theme(theme);
}
WindowEvent::RedrawRequested => {
if let Err(err) = window.draw() {
eprintln!("Error drawing window: {err}");
error!("Error drawing window: {err}");
}
}
WindowEvent::Occluded(occluded) => {
window.set_occluded(occluded);
}
WindowEvent::CloseRequested => {
println!("Closing Window={window_id:?}");
info!("Closing Window={window_id:?}");
self.windows.remove(&window_id);
}
WindowEvent::ModifiersChanged(modifiers) => {
window.modifiers = modifiers.state();
println!("Modifiers changed to {:?}", window.modifiers);
info!("Modifiers changed to {:?}", window.modifiers);
}
WindowEvent::MouseWheel { delta, .. } => match delta {
MouseScrollDelta::LineDelta(x, y) => {
println!("Mouse wheel Line Delta: ({x},{y})");
info!("Mouse wheel Line Delta: ({x},{y})");
}
MouseScrollDelta::PixelDelta(px) => {
println!("Mouse wheel Pixel Delta: ({},{})", px.x, px.y);
info!("Mouse wheel Pixel Delta: ({},{})", px.x, px.y);
}
},
WindowEvent::KeyboardInput {
@ -372,11 +392,11 @@ impl ApplicationHandler<UserEvent> for Application {
}
}
WindowEvent::CursorLeft { .. } => {
println!("Cursor left Window={window_id:?}");
info!("Cursor left Window={window_id:?}");
window.cursor_left();
}
WindowEvent::CursorMoved { position, .. } => {
println!("Moved cursor to {position:?}");
info!("Moved cursor to {position:?}");
window.cursor_moved(position);
}
WindowEvent::ActivationTokenDone { token: _token, .. } => {
@ -384,40 +404,40 @@ impl ApplicationHandler<UserEvent> for Application {
{
startup_notify::set_activation_token_env(_token);
if let Err(err) = self.create_window(event_loop, None) {
eprintln!("Error creating new window: {err}");
error!("Error creating new window: {err}");
}
}
}
WindowEvent::Ime(event) => match event {
Ime::Enabled => println!("IME enabled for Window={window_id:?}"),
Ime::Enabled => info!("IME enabled for Window={window_id:?}"),
Ime::Preedit(text, caret_pos) => {
println!("Preedit: {}, with caret at {:?}", text, caret_pos);
info!("Preedit: {}, with caret at {:?}", text, caret_pos);
}
Ime::Commit(text) => {
println!("Committed: {}", text);
info!("Committed: {}", text);
}
Ime::Disabled => println!("IME disabled for Window={window_id:?}"),
Ime::Disabled => info!("IME disabled for Window={window_id:?}"),
},
WindowEvent::PinchGesture { delta, .. } => {
window.zoom += delta;
let zoom = window.zoom;
if delta > 0.0 {
println!("Zoomed in {delta:.5} (now: {zoom:.5})");
info!("Zoomed in {delta:.5} (now: {zoom:.5})");
} else {
println!("Zoomed out {delta:.5} (now: {zoom:.5})");
info!("Zoomed out {delta:.5} (now: {zoom:.5})");
}
}
WindowEvent::RotationGesture { delta, .. } => {
window.rotated += delta;
let rotated = window.rotated;
if delta > 0.0 {
println!("Rotated counterclockwise {delta:.5} (now: {rotated:.5})");
info!("Rotated counterclockwise {delta:.5} (now: {rotated:.5})");
} else {
println!("Rotated clockwise {delta:.5} (now: {rotated:.5})");
info!("Rotated clockwise {delta:.5} (now: {rotated:.5})");
}
}
WindowEvent::DoubleTapGesture { .. } => {
println!("Smart zoom");
info!("Smart zoom");
}
WindowEvent::TouchpadPressure { .. }
| WindowEvent::HoveredFileCancelled
@ -438,11 +458,11 @@ impl ApplicationHandler<UserEvent> for Application {
device_id: DeviceId,
event: DeviceEvent,
) {
println!("Device {device_id:?} event: {event:?}");
info!("Device {device_id:?} event: {event:?}");
}
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
println!("Resumed the event loop");
info!("Resumed the event loop");
self.dump_monitors(event_loop);
// Create initial window.
@ -454,7 +474,7 @@ impl ApplicationHandler<UserEvent> for Application {
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
if self.windows.is_empty() {
println!("No windows left, exiting...");
info!("No windows left, exiting...");
event_loop.exit();
}
}
@ -509,7 +529,7 @@ impl WindowState {
let surface = unsafe { Surface::new(app.context.as_ref().unwrap(), &window)? };
let theme = window.theme().unwrap_or(Theme::Dark);
println!("Theme: {theme:?}");
info!("Theme: {theme:?}");
let named_idx = 0;
window.set_cursor(CURSORS[named_idx]);
@ -596,7 +616,7 @@ impl WindowState {
Some(_) => None,
None => Some(LogicalSize::new(25.0, 25.0)),
};
println!("Had increments: {}", new_increments.is_none());
info!("Had increments: {}", new_increments.is_none());
self.window.set_resize_increments(new_increments);
}
@ -618,9 +638,9 @@ impl WindowState {
CursorGrabMode::Confined => CursorGrabMode::Locked,
CursorGrabMode::Locked => CursorGrabMode::None,
};
println!("Changing cursor grab mode to {:?}", self.cursor_grab);
info!("Changing cursor grab mode to {:?}", self.cursor_grab);
if let Err(err) = self.window.set_cursor_grab(self.cursor_grab) {
eprintln!("Error setting cursor grab: {err}");
error!("Error setting cursor grab: {err}");
}
}
@ -632,7 +652,7 @@ impl WindowState {
OptionAsAlt::OnlyRight => OptionAsAlt::Both,
OptionAsAlt::Both => OptionAsAlt::None,
};
println!("Setting option as alt {:?}", self.option_as_alt);
info!("Setting option as alt {:?}", self.option_as_alt);
self.window.set_option_as_alt(self.option_as_alt);
}
@ -642,23 +662,23 @@ impl WindowState {
let mut inner_size = old_inner_size;
mem::swap(&mut inner_size.width, &mut inner_size.height);
println!("Requesting resize from {old_inner_size:?} to {inner_size:?}");
info!("Requesting resize from {old_inner_size:?} to {inner_size:?}");
if let Some(new_inner_size) = self.window.request_inner_size(inner_size) {
if old_inner_size == new_inner_size {
println!("Inner size change got ignored");
info!("Inner size change got ignored");
} else {
self.resize(new_inner_size);
}
} else {
println!("Request inner size is asynchronous");
info!("Request inner size is asynchronous");
}
}
/// Pick the next cursor.
fn next_cursor(&mut self) {
self.named_idx = (self.named_idx + 1) % CURSORS.len();
println!("Setting cursor to \"{:?}\"", CURSORS[self.named_idx]);
info!("Setting cursor to \"{:?}\"", CURSORS[self.named_idx]);
self.window
.set_cursor(Cursor::Icon(CURSORS[self.named_idx]));
}
@ -670,9 +690,38 @@ impl WindowState {
self.window.set_cursor(cursor);
}
/// Custom cursor from an URL.
#[cfg(web_platform)]
fn url_custom_cursor(&mut self, event_loop: &ActiveEventLoop) {
let cursor = event_loop.create_custom_cursor(url_custom_cursor());
self.window.set_cursor(cursor);
}
/// Custom cursor from a URL.
#[cfg(web_platform)]
fn animation_custom_cursor(
&mut self,
event_loop: &ActiveEventLoop,
custom_cursors: &[CustomCursor],
) {
use std::time::Duration;
use winit::platform::web::CustomCursorExtWebSys;
let cursors = vec![
custom_cursors[0].clone(),
custom_cursors[1].clone(),
event_loop.create_custom_cursor(url_custom_cursor()),
];
let cursor = CustomCursor::from_animation(Duration::from_secs(3), cursors).unwrap();
let cursor = event_loop.create_custom_cursor(cursor);
self.window.set_cursor(cursor);
}
/// Resize the window to the new size.
fn resize(&mut self, size: PhysicalSize<u32>) {
println!("Resized to {size:?}");
info!("Resized to {size:?}");
#[cfg(not(any(android_platform, ios_platform)))]
{
let (width, height) = match (NonZeroU32::new(size.width), NonZeroU32::new(size.height))
@ -703,9 +752,9 @@ impl WindowState {
/// Drag the window.
fn drag_window(&self) {
if let Err(err) = self.window.drag_window() {
println!("Error starting window drag: {err}");
info!("Error starting window drag: {err}");
} else {
println!("Dragging window Window={:?}", self.window.id());
info!("Dragging window Window={:?}", self.window.id());
}
}
@ -714,7 +763,7 @@ impl WindowState {
let position = match self.cursor_position {
Some(position) => position,
None => {
println!("Drag-resize requires cursor to be inside the window");
info!("Drag-resize requires cursor to be inside the window");
return;
}
};
@ -753,9 +802,9 @@ impl WindowState {
};
if let Err(err) = self.window.drag_resize_window(direction) {
println!("Error starting window drag-resize: {err}");
info!("Error starting window drag-resize: {err}");
} else {
println!("Drag-resizing window Window={:?}", self.window.id());
info!("Drag-resizing window Window={:?}", self.window.id());
}
}
@ -771,7 +820,7 @@ impl WindowState {
#[cfg(not(any(android_platform, ios_platform)))]
fn draw(&mut self) -> Result<(), Box<dyn Error>> {
if self.occluded {
println!("Skipping drawing occluded window={:?}", self.window.id());
info!("Skipping drawing occluded window={:?}", self.window.id());
return Ok(());
}
@ -792,7 +841,7 @@ impl WindowState {
#[cfg(any(android_platform, ios_platform))]
fn draw(&mut self) -> Result<(), Box<dyn Error>> {
println!("Drawing but without rendering...");
info!("Drawing but without rendering...");
Ok(())
}
}
@ -831,6 +880,10 @@ enum Action {
Minimize,
NextCursor,
NextCustomCursor,
#[cfg(web_platform)]
UrlCustomCursor,
#[cfg(web_platform)]
AnimationCustomCursor,
CycleCursorGrab,
PrintHelp,
DragWindow,
@ -858,6 +911,10 @@ impl Action {
Action::ToggleResizeIncrements => "Use resize increments when resizing window",
Action::NextCursor => "Advance the cursor to the next value",
Action::NextCustomCursor => "Advance custom cursor to the next value",
#[cfg(web_platform)]
Action::UrlCustomCursor => "Custom cursor from an URL",
#[cfg(web_platform)]
Action::AnimationCustomCursor => "Custom cursor from an animation",
Action::CycleCursorGrab => "Cycle through cursor grab mode",
Action::PrintHelp => "Print help",
Action::DragWindow => "Start window drag",
@ -886,11 +943,27 @@ fn decode_cursor(bytes: &[u8]) -> CustomCursorSource {
CustomCursor::from_rgba(samples.samples, w, h, w / 2, h / 2).unwrap()
}
fn load_icon(path: &Path) -> Icon {
#[cfg(web_platform)]
fn url_custom_cursor() -> CustomCursorSource {
use std::sync::atomic::{AtomicU64, Ordering};
use winit::platform::web::CustomCursorExtWebSys;
static URL_COUNTER: AtomicU64 = AtomicU64::new(0);
CustomCursor::from_url(
format!(
"https://picsum.photos/128?random={}",
URL_COUNTER.fetch_add(1, Ordering::Relaxed)
),
64,
64,
)
}
fn load_icon(bytes: &[u8]) -> Icon {
let (icon_rgba, icon_width, icon_height) = {
let image = image::open(path)
.expect("Failed to open icon path")
.into_rgba8();
let image = image::load_from_memory(bytes).unwrap().into_rgba8();
let (width, height) = image.dimensions();
let rgba = image.into_raw();
(rgba, width, height)
@ -983,6 +1056,18 @@ const KEY_BINDINGS: &[Binding<&'static str>] = &[
// C.
Binding::new("C", ModifiersState::CONTROL, Action::NextCursor),
Binding::new("C", ModifiersState::ALT, Action::NextCustomCursor),
#[cfg(web_platform)]
Binding::new(
"C",
ModifiersState::CONTROL.union(ModifiersState::SHIFT),
Action::UrlCustomCursor,
),
#[cfg(web_platform)]
Binding::new(
"C",
ModifiersState::ALT.union(ModifiersState::SHIFT),
Action::AnimationCustomCursor,
),
Binding::new("Z", ModifiersState::CONTROL, Action::ToggleCursorVisibility),
#[cfg(macos_platform)]
Binding::new("T", ModifiersState::SUPER, Action::CreateNewTab),

View File

@ -1,11 +0,0 @@
[package]
name = "run-wasm"
version = "0.1.0"
rust-version.workspace = true
repository.workspace = true
license.workspace = true
edition.workspace = true
publish = false
[dependencies]
cargo-run-wasm = "0.2.0"

View File

@ -1,3 +0,0 @@
fn main() {
cargo_run_wasm::run_wasm_with_css("body { margin: 0px; }");
}