bevy/crates/bevy_winit/src/winit_windows.rs

169 lines
5.8 KiB
Rust
Raw Normal View History

use bevy_utils::HashMap;
use bevy_window::{Window, WindowId, WindowMode};
2020-03-30 21:53:32 +00:00
#[derive(Debug, Default)]
2020-03-30 21:53:32 +00:00
pub struct WinitWindows {
pub windows: HashMap<winit::window::WindowId, winit::window::Window>,
pub window_id_to_winit: HashMap<WindowId, winit::window::WindowId>,
pub winit_to_window_id: HashMap<winit::window::WindowId, WindowId>,
}
impl WinitWindows {
pub fn create_window(
&mut self,
event_loop: &winit::event_loop::EventLoopWindowTarget<()>,
window: &mut Window,
2020-03-30 21:53:32 +00:00
) {
2020-07-26 19:36:01 +00:00
#[cfg(target_os = "windows")]
let mut winit_window_builder = {
2020-07-26 19:36:01 +00:00
use winit::platform::windows::WindowBuilderExtWindows;
winit::window::WindowBuilder::new().with_drag_and_drop(false)
2020-07-26 19:36:01 +00:00
};
#[cfg(not(target_os = "windows"))]
let mut winit_window_builder = winit::window::WindowBuilder::new();
winit_window_builder = match window.mode() {
WindowMode::BorderlessFullscreen => winit_window_builder.with_fullscreen(Some(
winit::window::Fullscreen::Borderless(event_loop.primary_monitor()),
)),
WindowMode::Fullscreen { use_size } => winit_window_builder.with_fullscreen(Some(
winit::window::Fullscreen::Exclusive(match use_size {
true => get_fitting_videomode(
&event_loop.primary_monitor().unwrap(),
window.width(),
window.height(),
),
false => get_best_videomode(&event_loop.primary_monitor().unwrap()),
}),
)),
_ => winit_window_builder
.with_inner_size(winit::dpi::LogicalSize::new(
window.width(),
window.height(),
))
.with_resizable(window.resizable())
.with_decorations(window.decorations()),
};
2020-07-26 19:36:01 +00:00
#[allow(unused_mut)]
let mut winit_window_builder = winit_window_builder.with_title(window.title());
#[cfg(target_arch = "wasm32")]
{
use wasm_bindgen::JsCast;
use winit::platform::web::WindowBuilderExtWebSys;
if let Some(selector) = &window.canvas {
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let canvas = document
.query_selector(&selector)
.expect("Cannot query for canvas element");
if let Some(canvas) = canvas {
let canvas = canvas.dyn_into::<web_sys::HtmlCanvasElement>().ok();
winit_window_builder = winit_window_builder.with_canvas(canvas);
} else {
panic!("Cannot find element: {}", selector);
}
}
}
let winit_window = winit_window_builder.build(&event_loop).unwrap();
match winit_window.set_cursor_grab(window.cursor_locked()) {
Ok(_) => {}
Err(winit::error::ExternalError::NotSupported(_)) => {}
Err(err) => Err(err).unwrap(),
}
winit_window.set_cursor_visible(window.cursor_visible());
self.window_id_to_winit
.insert(window.id(), winit_window.id());
self.winit_to_window_id
.insert(winit_window.id(), window.id());
2020-03-30 21:53:32 +00:00
#[cfg(target_arch = "wasm32")]
{
use winit::platform::web::WindowExtWebSys;
if window.canvas.is_none() {
let canvas = winit_window.canvas();
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let body = document.body().unwrap();
body.append_child(&canvas)
.expect("Append canvas to HTML body");
}
}
window.update_scale_factor_from_backend(winit_window.scale_factor());
2020-03-30 21:53:32 +00:00
self.windows.insert(winit_window.id(), winit_window);
}
pub fn get_window(&self, id: WindowId) -> Option<&winit::window::Window> {
self.window_id_to_winit
.get(&id)
.and_then(|id| self.windows.get(id))
}
pub fn get_window_id(&self, id: winit::window::WindowId) -> Option<WindowId> {
self.winit_to_window_id.get(&id).cloned()
}
}
pub fn get_fitting_videomode(
monitor: &winit::monitor::MonitorHandle,
width: u32,
height: u32,
) -> winit::monitor::VideoMode {
let mut modes = monitor.video_modes().collect::<Vec<_>>();
fn abs_diff(a: u32, b: u32) -> u32 {
if a > b {
return a - b;
}
b - a
}
modes.sort_by(|a, b| {
use std::cmp::Ordering::*;
match abs_diff(a.size().width, width).cmp(&abs_diff(b.size().width, width)) {
Equal => {
match abs_diff(a.size().height, height).cmp(&abs_diff(b.size().height, height)) {
Equal => b.refresh_rate().cmp(&a.refresh_rate()),
default => default,
}
}
default => default,
}
});
modes.first().unwrap().clone()
}
pub fn get_best_videomode(monitor: &winit::monitor::MonitorHandle) -> winit::monitor::VideoMode {
let mut modes = monitor.video_modes().collect::<Vec<_>>();
modes.sort_by(|a, b| {
use std::cmp::Ordering::*;
match b.size().width.cmp(&a.size().width) {
Equal => match b.size().height.cmp(&a.size().height) {
Equal => b.refresh_rate().cmp(&a.refresh_rate()),
default => default,
},
default => default,
}
});
modes.first().unwrap().clone()
}
// WARNING: this only works under the assumption that wasm runtime is single threaded
#[cfg(target_arch = "wasm32")]
unsafe impl Send for WinitWindows {}
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for WinitWindows {}