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