Make raw_window_handle
field in Window
and ExtractedWindow
an Option
. (#6114)
# Objective - Trying to make it possible to do write tests that don't require a raw window handle. - Fixes https://github.com/bevyengine/bevy/issues/6106. ## Solution - Make the interface and type changes. Avoid accessing `None`. --- ## Changelog - Converted `raw_window_handle` field in both `Window` and `ExtractedWindow` to `Option<RawWindowHandleWrapper>`. - Revised accessor function `Window::raw_window_handle()` to return `Option<RawWindowHandleWrapper>`. - Skip conditions in loops that would require a raw window handle (to create a `Surface`, for example). ## Migration Guide `Window::raw_window_handle()` now returns `Option<RawWindowHandleWrapper>`. Co-authored-by: targrub <62773321+targrub@users.noreply.github.com>
This commit is contained in:
parent
bfd6285c3b
commit
964b047466
@ -144,14 +144,21 @@ impl Plugin for RenderPlugin {
|
|||||||
.register_type::<Color>();
|
.register_type::<Color>();
|
||||||
|
|
||||||
if let Some(backends) = options.backends {
|
if let Some(backends) = options.backends {
|
||||||
|
let windows = app.world.resource_mut::<bevy_window::Windows>();
|
||||||
let instance = wgpu::Instance::new(backends);
|
let instance = wgpu::Instance::new(backends);
|
||||||
let surface = {
|
let surface = {
|
||||||
let windows = app.world.resource_mut::<bevy_window::Windows>();
|
if let Some(window) = windows.get_primary() {
|
||||||
let raw_handle = windows.get_primary().map(|window| unsafe {
|
if let Some(raw_window_handle) = window.raw_window_handle() {
|
||||||
let handle = window.raw_window_handle().get_handle();
|
unsafe {
|
||||||
instance.create_surface(&handle)
|
let handle = raw_window_handle.get_handle();
|
||||||
});
|
Some(instance.create_surface(&handle))
|
||||||
raw_handle
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let request_adapter_options = wgpu::RequestAdapterOptions {
|
let request_adapter_options = wgpu::RequestAdapterOptions {
|
||||||
power_preference: options.power_preference,
|
power_preference: options.power_preference,
|
||||||
|
@ -38,7 +38,7 @@ impl Plugin for WindowRenderPlugin {
|
|||||||
|
|
||||||
pub struct ExtractedWindow {
|
pub struct ExtractedWindow {
|
||||||
pub id: WindowId,
|
pub id: WindowId,
|
||||||
pub handle: RawWindowHandleWrapper,
|
pub raw_window_handle: Option<RawWindowHandleWrapper>,
|
||||||
pub physical_width: u32,
|
pub physical_width: u32,
|
||||||
pub physical_height: u32,
|
pub physical_height: u32,
|
||||||
pub present_mode: PresentMode,
|
pub present_mode: PresentMode,
|
||||||
@ -83,7 +83,7 @@ fn extract_windows(
|
|||||||
.entry(window.id())
|
.entry(window.id())
|
||||||
.or_insert(ExtractedWindow {
|
.or_insert(ExtractedWindow {
|
||||||
id: window.id(),
|
id: window.id(),
|
||||||
handle: window.raw_window_handle(),
|
raw_window_handle: window.raw_window_handle(),
|
||||||
physical_width: new_width,
|
physical_width: new_width,
|
||||||
physical_height: new_height,
|
physical_height: new_height,
|
||||||
present_mode: window.present_mode(),
|
present_mode: window.present_mode(),
|
||||||
@ -161,14 +161,20 @@ pub fn prepare_windows(
|
|||||||
render_instance: Res<RenderInstance>,
|
render_instance: Res<RenderInstance>,
|
||||||
render_adapter: Res<RenderAdapter>,
|
render_adapter: Res<RenderAdapter>,
|
||||||
) {
|
) {
|
||||||
let window_surfaces = window_surfaces.deref_mut();
|
for window in windows
|
||||||
for window in windows.windows.values_mut() {
|
.windows
|
||||||
|
.values_mut()
|
||||||
|
// value of raw_winndow_handle only None if synthetic test
|
||||||
|
.filter(|x| x.raw_window_handle.is_some())
|
||||||
|
{
|
||||||
|
let window_surfaces = window_surfaces.deref_mut();
|
||||||
let surface = window_surfaces
|
let surface = window_surfaces
|
||||||
.surfaces
|
.surfaces
|
||||||
.entry(window.id)
|
.entry(window.id)
|
||||||
.or_insert_with(|| unsafe {
|
.or_insert_with(|| unsafe {
|
||||||
// NOTE: On some OSes this MUST be called from the main thread.
|
// NOTE: On some OSes this MUST be called from the main thread.
|
||||||
render_instance.create_surface(&window.handle.get_handle())
|
render_instance
|
||||||
|
.create_surface(&window.raw_window_handle.as_ref().unwrap().get_handle())
|
||||||
});
|
});
|
||||||
|
|
||||||
let swap_chain_descriptor = wgpu::SurfaceConfiguration {
|
let swap_chain_descriptor = wgpu::SurfaceConfiguration {
|
||||||
|
@ -187,6 +187,59 @@ impl WindowResizeConstraints {
|
|||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
/// To test code that uses `Window`s, one can test it with varying `Window` parameters by
|
||||||
|
/// creating `WindowResizeConstraints` or `WindowDescriptor` structures.
|
||||||
|
/// values by setting
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bevy_utils::default;
|
||||||
|
/// # use bevy_window::{Window, WindowCommand, WindowDescriptor, WindowId, WindowResizeConstraints};
|
||||||
|
/// # fn compute_window_area(w: &Window) -> f32 {
|
||||||
|
/// # w.width() * w.height()
|
||||||
|
/// # }
|
||||||
|
/// # fn grow_window_to_text_size(_window: &mut Window, _text: &str) {}
|
||||||
|
/// # fn set_new_title(window: &mut Window, text: String) { window.set_title(text); }
|
||||||
|
/// # fn a_window_resize_test() {
|
||||||
|
/// let resize_constraints = WindowResizeConstraints {
|
||||||
|
/// min_width: 400.0,
|
||||||
|
/// min_height: 300.0,
|
||||||
|
/// max_width: 1280.0,
|
||||||
|
/// max_height: 1024.0,
|
||||||
|
/// };
|
||||||
|
/// let window_descriptor = WindowDescriptor {
|
||||||
|
/// width: 800.0,
|
||||||
|
/// height: 600.0,
|
||||||
|
/// resizable: true,
|
||||||
|
/// resize_constraints,
|
||||||
|
/// ..default()
|
||||||
|
/// };
|
||||||
|
/// let mut window = Window::new(
|
||||||
|
/// WindowId::new(),
|
||||||
|
/// &window_descriptor,
|
||||||
|
/// 100, // physical_width
|
||||||
|
/// 100, // physical_height
|
||||||
|
/// 1.0, // scale_factor
|
||||||
|
/// None, None);
|
||||||
|
///
|
||||||
|
/// let area = compute_window_area(&window);
|
||||||
|
/// assert_eq!(area, 100.0 * 100.0);
|
||||||
|
///
|
||||||
|
/// grow_window_to_text_size(&mut window, "very long text that does not wrap");
|
||||||
|
/// assert_eq!(window.physical_width(), window.requested_width() as u32);
|
||||||
|
/// grow_window_to_text_size(&mut window, "very long text that does wrap, creating a maximum width window");
|
||||||
|
/// assert_eq!(window.physical_width(), window.requested_width() as u32);
|
||||||
|
///
|
||||||
|
/// set_new_title(&mut window, "new title".to_string());
|
||||||
|
/// let mut found_command = false;
|
||||||
|
/// for command in window.drain_commands() {
|
||||||
|
/// if command == (WindowCommand::SetTitle{ title: "new title".to_string() }) {
|
||||||
|
/// found_command = true;
|
||||||
|
/// break;
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// assert_eq!(found_command, true);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
id: WindowId,
|
id: WindowId,
|
||||||
@ -206,7 +259,7 @@ pub struct Window {
|
|||||||
cursor_visible: bool,
|
cursor_visible: bool,
|
||||||
cursor_locked: bool,
|
cursor_locked: bool,
|
||||||
physical_cursor_position: Option<DVec2>,
|
physical_cursor_position: Option<DVec2>,
|
||||||
raw_window_handle: RawWindowHandleWrapper,
|
raw_window_handle: Option<RawWindowHandleWrapper>,
|
||||||
focused: bool,
|
focused: bool,
|
||||||
mode: WindowMode,
|
mode: WindowMode,
|
||||||
canvas: Option<String>,
|
canvas: Option<String>,
|
||||||
@ -217,7 +270,7 @@ pub struct Window {
|
|||||||
///
|
///
|
||||||
/// Bevy apps don't interact with this `enum` directly. Instead, they should use the methods on [`Window`].
|
/// Bevy apps don't interact with this `enum` directly. Instead, they should use the methods on [`Window`].
|
||||||
/// This `enum` is meant for authors of windowing plugins. See the documentation on [`crate::WindowPlugin`] for more information.
|
/// This `enum` is meant for authors of windowing plugins. See the documentation on [`crate::WindowPlugin`] for more information.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq)]
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub enum WindowCommand {
|
pub enum WindowCommand {
|
||||||
/// Set the window's [`WindowMode`].
|
/// Set the window's [`WindowMode`].
|
||||||
@ -315,7 +368,7 @@ impl Window {
|
|||||||
physical_height: u32,
|
physical_height: u32,
|
||||||
scale_factor: f64,
|
scale_factor: f64,
|
||||||
position: Option<IVec2>,
|
position: Option<IVec2>,
|
||||||
raw_window_handle: RawWindowHandle,
|
raw_window_handle: Option<RawWindowHandle>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Window {
|
Window {
|
||||||
id,
|
id,
|
||||||
@ -335,7 +388,7 @@ impl Window {
|
|||||||
cursor_locked: window_descriptor.cursor_locked,
|
cursor_locked: window_descriptor.cursor_locked,
|
||||||
cursor_icon: CursorIcon::Default,
|
cursor_icon: CursorIcon::Default,
|
||||||
physical_cursor_position: None,
|
physical_cursor_position: None,
|
||||||
raw_window_handle: RawWindowHandleWrapper::new(raw_window_handle),
|
raw_window_handle: raw_window_handle.map(RawWindowHandleWrapper::new),
|
||||||
focused: true,
|
focused: true,
|
||||||
mode: window_descriptor.mode,
|
mode: window_descriptor.mode,
|
||||||
canvas: window_descriptor.canvas.clone(),
|
canvas: window_descriptor.canvas.clone(),
|
||||||
@ -719,9 +772,11 @@ impl Window {
|
|||||||
pub fn is_focused(&self) -> bool {
|
pub fn is_focused(&self) -> bool {
|
||||||
self.focused
|
self.focused
|
||||||
}
|
}
|
||||||
/// Get the [`RawWindowHandleWrapper`] corresponding to this window
|
/// Get the [`RawWindowHandleWrapper`] corresponding to this window if set.
|
||||||
pub fn raw_window_handle(&self) -> RawWindowHandleWrapper {
|
///
|
||||||
self.raw_window_handle.clone()
|
/// During normal use, this can be safely unwrapped; the value should only be [`None`] when synthetically constructed for tests.
|
||||||
|
pub fn raw_window_handle(&self) -> Option<RawWindowHandleWrapper> {
|
||||||
|
self.raw_window_handle.as_ref().cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The "html canvas" element selector.
|
/// The "html canvas" element selector.
|
||||||
|
@ -201,7 +201,7 @@ impl WinitWindows {
|
|||||||
inner_size.height,
|
inner_size.height,
|
||||||
scale_factor,
|
scale_factor,
|
||||||
position,
|
position,
|
||||||
raw_window_handle,
|
Some(raw_window_handle),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user