parent
9a28bb4b49
commit
8cc5cb9d9b
13 changed files with 141 additions and 69 deletions
|
|
@ -24,6 +24,7 @@ Unreleased` header.
|
|||
- **Breaking:** On Web, macOS and iOS, return `HandleError::Unavailable` when a window handle is not available.
|
||||
- **Breaking:** Bump MSRV from `1.65` to `1.70`.
|
||||
- On Wayland, fix `WindowEvent::Destroyed` not being delivered after destroying window.
|
||||
- Fix `EventLoopExtRunOnDemand::run_on_demand` not working for consequent invocation
|
||||
|
||||
# 0.29.5
|
||||
|
||||
|
|
|
|||
|
|
@ -7,17 +7,30 @@
|
|||
//! The `softbuffer` crate is used, largely because of its ease of use. `glutin` or `wgpu` could
|
||||
//! also be used to fill the window buffer, but they are more complicated to use.
|
||||
|
||||
use winit::window::Window;
|
||||
#[allow(unused_imports)]
|
||||
pub use platform::cleanup_window;
|
||||
pub use platform::fill_window;
|
||||
|
||||
#[cfg(all(feature = "rwh_05", not(any(target_os = "android", target_os = "ios"))))]
|
||||
pub(super) fn fill_window(window: &Window) {
|
||||
use softbuffer::{Context, Surface};
|
||||
mod platform {
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use softbuffer::{Context, Surface};
|
||||
use winit::window::Window;
|
||||
use winit::window::WindowId;
|
||||
|
||||
thread_local! {
|
||||
// NOTE: You should never do things like that, create context and drop it before
|
||||
// you drop the event loop. We do this for brevity to not blow up examples. We use
|
||||
// ManuallyDrop to prevent destructors from running.
|
||||
//
|
||||
// A static, thread-local map of graphics contexts to open windows.
|
||||
static GC: ManuallyDrop<RefCell<Option<GraphicsContext>>> = ManuallyDrop::new(RefCell::new(None));
|
||||
}
|
||||
|
||||
/// The graphics context used to draw to a window.
|
||||
struct GraphicsContext {
|
||||
/// The global softbuffer context.
|
||||
|
|
@ -35,55 +48,69 @@ pub(super) fn fill_window(window: &Window) {
|
|||
}
|
||||
}
|
||||
|
||||
fn surface(&mut self, w: &Window) -> &mut Surface {
|
||||
self.surfaces.entry(w.id()).or_insert_with(|| {
|
||||
unsafe { Surface::new(&self.context, w) }
|
||||
fn create_surface(&mut self, window: &Window) -> &mut Surface {
|
||||
self.surfaces.entry(window.id()).or_insert_with(|| {
|
||||
unsafe { Surface::new(&self.context, window) }
|
||||
.expect("Failed to create a softbuffer surface")
|
||||
})
|
||||
}
|
||||
|
||||
fn destroy_surface(&mut self, window: &Window) {
|
||||
self.surfaces.remove(&window.id());
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
// NOTE: You should never do things like that, create context and drop it before
|
||||
// you drop the event loop. We do this for brevity to not blow up examples. We use
|
||||
// ManuallyDrop to prevent destructors from running.
|
||||
//
|
||||
// A static, thread-local map of graphics contexts to open windows.
|
||||
static GC: ManuallyDrop<RefCell<Option<GraphicsContext>>> = ManuallyDrop::new(RefCell::new(None));
|
||||
pub fn fill_window(window: &Window) {
|
||||
GC.with(|gc| {
|
||||
let size = window.inner_size();
|
||||
let (Some(width), Some(height)) =
|
||||
(NonZeroU32::new(size.width), NonZeroU32::new(size.height))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Either get the last context used or create a new one.
|
||||
let mut gc = gc.borrow_mut();
|
||||
let surface = gc
|
||||
.get_or_insert_with(|| GraphicsContext::new(window))
|
||||
.create_surface(window);
|
||||
|
||||
// Fill a buffer with a solid color.
|
||||
const DARK_GRAY: u32 = 0xFF181818;
|
||||
|
||||
surface
|
||||
.resize(width, height)
|
||||
.expect("Failed to resize the softbuffer surface");
|
||||
|
||||
let mut buffer = surface
|
||||
.buffer_mut()
|
||||
.expect("Failed to get the softbuffer buffer");
|
||||
buffer.fill(DARK_GRAY);
|
||||
buffer
|
||||
.present()
|
||||
.expect("Failed to present the softbuffer buffer");
|
||||
})
|
||||
}
|
||||
|
||||
GC.with(|gc| {
|
||||
let size = window.inner_size();
|
||||
let (Some(width), Some(height)) =
|
||||
(NonZeroU32::new(size.width), NonZeroU32::new(size.height))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Either get the last context used or create a new one.
|
||||
let mut gc = gc.borrow_mut();
|
||||
let surface = gc
|
||||
.get_or_insert_with(|| GraphicsContext::new(window))
|
||||
.surface(window);
|
||||
|
||||
// Fill a buffer with a solid color.
|
||||
const DARK_GRAY: u32 = 0xFF181818;
|
||||
|
||||
surface
|
||||
.resize(width, height)
|
||||
.expect("Failed to resize the softbuffer surface");
|
||||
|
||||
let mut buffer = surface
|
||||
.buffer_mut()
|
||||
.expect("Failed to get the softbuffer buffer");
|
||||
buffer.fill(DARK_GRAY);
|
||||
buffer
|
||||
.present()
|
||||
.expect("Failed to present the softbuffer buffer");
|
||||
})
|
||||
#[allow(dead_code)]
|
||||
pub fn cleanup_window(window: &Window) {
|
||||
GC.with(|gc| {
|
||||
let mut gc = gc.borrow_mut();
|
||||
if let Some(context) = gc.as_mut() {
|
||||
context.destroy_surface(window);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(all(feature = "rwh_05", not(any(target_os = "android", target_os = "ios")))))]
|
||||
pub(super) fn fill_window(_window: &Window) {
|
||||
// No-op on mobile platforms.
|
||||
mod platform {
|
||||
pub fn fill_window(_window: &winit::window::Window) {
|
||||
// No-op on mobile platforms.
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn cleanup_window(_window: &winit::window::Window) {
|
||||
// No-op on mobile platforms.
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ fn main() -> Result<(), impl std::error::Error> {
|
|||
window_id,
|
||||
} if window.id() == window_id => {
|
||||
println!("--------------------------------------------------------- Window {idx} CloseRequested");
|
||||
fill::cleanup_window(window);
|
||||
app.window = None;
|
||||
}
|
||||
Event::AboutToWait => window.request_redraw(),
|
||||
|
|
|
|||
|
|
@ -76,6 +76,14 @@ impl<T> EventLoopExtRunOnDemand for EventLoop<T> {
|
|||
where
|
||||
F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>),
|
||||
{
|
||||
self.event_loop.window_target().clear_exit();
|
||||
self.event_loop.run_on_demand(event_handler)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> EventLoopWindowTarget<T> {
|
||||
/// Clear exit status.
|
||||
pub(crate) fn clear_exit(&self) {
|
||||
self.p.clear_exit()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -713,6 +713,10 @@ impl<T: 'static> EventLoopWindowTarget<T> {
|
|||
self.exit.set(true)
|
||||
}
|
||||
|
||||
pub(crate) fn clear_exit(&self) {
|
||||
self.exit.set(false)
|
||||
}
|
||||
|
||||
pub(crate) fn exiting(&self) -> bool {
|
||||
self.exit.get()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -925,6 +925,10 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
x11_or_wayland!(match self; Self(evlp) => evlp.control_flow())
|
||||
}
|
||||
|
||||
pub(crate) fn clear_exit(&self) {
|
||||
x11_or_wayland!(match self; Self(evlp) => evlp.clear_exit())
|
||||
}
|
||||
|
||||
pub(crate) fn exit(&self) {
|
||||
x11_or_wayland!(match self; Self(evlp) => evlp.exit())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -629,6 +629,34 @@ pub struct EventLoopWindowTarget<T> {
|
|||
}
|
||||
|
||||
impl<T> EventLoopWindowTarget<T> {
|
||||
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
|
||||
self.control_flow.set(control_flow)
|
||||
}
|
||||
|
||||
pub(crate) fn control_flow(&self) -> ControlFlow {
|
||||
self.control_flow.get()
|
||||
}
|
||||
|
||||
pub(crate) fn exit(&self) {
|
||||
self.exit.set(Some(0))
|
||||
}
|
||||
|
||||
pub(crate) fn clear_exit(&self) {
|
||||
self.exit.set(None)
|
||||
}
|
||||
|
||||
pub(crate) fn exiting(&self) -> bool {
|
||||
self.exit.get().is_some()
|
||||
}
|
||||
|
||||
pub(crate) fn set_exit_code(&self, code: i32) {
|
||||
self.exit.set(Some(code))
|
||||
}
|
||||
|
||||
pub(crate) fn exit_code(&self) -> Option<i32> {
|
||||
self.exit.get()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn listen_device_events(&self, _allowed: DeviceEvents) {}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ use sctk::reexports::client::Proxy;
|
|||
use sctk::output::OutputData;
|
||||
|
||||
use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
|
||||
use crate::event_loop::ControlFlow;
|
||||
use crate::platform_impl::platform::VideoMode as PlatformVideoMode;
|
||||
|
||||
use super::event_loop::EventLoopWindowTarget;
|
||||
|
|
@ -24,30 +23,6 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
// There's no primary monitor on Wayland.
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
|
||||
self.control_flow.set(control_flow)
|
||||
}
|
||||
|
||||
pub(crate) fn control_flow(&self) -> ControlFlow {
|
||||
self.control_flow.get()
|
||||
}
|
||||
|
||||
pub(crate) fn exit(&self) {
|
||||
self.exit.set(Some(0))
|
||||
}
|
||||
|
||||
pub(crate) fn exiting(&self) -> bool {
|
||||
self.exit.get().is_some()
|
||||
}
|
||||
|
||||
pub(crate) fn set_exit_code(&self, code: i32) {
|
||||
self.exit.set(Some(code))
|
||||
}
|
||||
|
||||
pub(crate) fn exit_code(&self) -> Option<i32> {
|
||||
self.exit.get()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
|
|||
|
|
@ -752,6 +752,10 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
self.exit.set(Some(0))
|
||||
}
|
||||
|
||||
pub(crate) fn clear_exit(&self) {
|
||||
self.exit.set(None)
|
||||
}
|
||||
|
||||
pub(crate) fn exiting(&self) -> bool {
|
||||
self.exit.get().is_some()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -210,6 +210,10 @@ impl Handler {
|
|||
self.exit.store(true, Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn clear_exit(&self) {
|
||||
self.exit.store(false, Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn exiting(&self) -> bool {
|
||||
self.exit.load(Ordering::Relaxed)
|
||||
}
|
||||
|
|
@ -435,6 +439,10 @@ impl AppState {
|
|||
HANDLER.exit()
|
||||
}
|
||||
|
||||
pub fn clear_exit() {
|
||||
HANDLER.clear_exit()
|
||||
}
|
||||
|
||||
pub fn exiting() -> bool {
|
||||
HANDLER.exiting()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,6 +122,10 @@ impl<T: 'static> EventLoopWindowTarget<T> {
|
|||
AppState::exit()
|
||||
}
|
||||
|
||||
pub(crate) fn clear_exit(&self) {
|
||||
AppState::clear_exit()
|
||||
}
|
||||
|
||||
pub(crate) fn exiting(&self) -> bool {
|
||||
AppState::exiting()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -530,6 +530,10 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
self.runner_shared.exit_code().is_some()
|
||||
}
|
||||
|
||||
pub(crate) fn clear_exit(&self) {
|
||||
self.runner_shared.clear_exit();
|
||||
}
|
||||
|
||||
fn exit_code(&self) -> Option<i32> {
|
||||
self.runner_shared.exit_code()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,6 +163,10 @@ impl<T> EventLoopRunner<T> {
|
|||
self.exit.get()
|
||||
}
|
||||
|
||||
pub fn clear_exit(&self) {
|
||||
self.exit.set(None);
|
||||
}
|
||||
|
||||
pub fn should_buffer(&self) -> bool {
|
||||
let handler = self.event_handler.take();
|
||||
let should_buffer = handler.is_none();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue