mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-26 14:49:07 -04:00
chore: avoid unsafe in examples
By using `OwnedDisplayHandle`, which uses reference-counting, instead of `DisplayHandle<'static>` (where the user has to guarantee that the Application doesn't outlive the event loop).
This commit is contained in:
@@ -76,9 +76,13 @@ winit-core.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
image = { workspace = true, features = ["png"] }
|
||||
softbuffer.workspace = true
|
||||
tracing = { workspace = true, features = ["log"] }
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter"] }
|
||||
# Launching a window without drawing to it has unpredictable results varying from platform to
|
||||
# platform. We use the `softbuffer` crate in our examples because of its ease of use to avoid
|
||||
# confusion around this. `glutin` or `wgpu` could also be used to fill the window buffer, but they
|
||||
# are more complicated to set up.
|
||||
softbuffer.workspace = true
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
winit-android.workspace = true
|
||||
|
||||
@@ -15,7 +15,6 @@ use std::time::Instant;
|
||||
use std::{fmt, mem};
|
||||
|
||||
use cursor_icon::CursorIcon;
|
||||
use rwh_06::{DisplayHandle, HasDisplayHandle};
|
||||
use softbuffer::{Context, Surface};
|
||||
use tracing::{error, info};
|
||||
#[cfg(web_platform)]
|
||||
@@ -25,7 +24,7 @@ use winit::cursor::{Cursor, CustomCursor, CustomCursorSource};
|
||||
use winit::dpi::{LogicalSize, PhysicalPosition, PhysicalSize};
|
||||
use winit::error::RequestError;
|
||||
use winit::event::{DeviceEvent, DeviceId, MouseButton, MouseScrollDelta, WindowEvent};
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop, OwnedDisplayHandle};
|
||||
use winit::icon::{Icon, RgbaIcon};
|
||||
use winit::keyboard::{Key, ModifiersState};
|
||||
use winit::monitor::Fullscreen;
|
||||
@@ -45,9 +44,6 @@ use winit_core::application::macos::ApplicationHandlerExtMacOS;
|
||||
#[path = "util/tracing.rs"]
|
||||
mod tracing_init;
|
||||
|
||||
#[path = "util/fill.rs"]
|
||||
mod fill;
|
||||
|
||||
/// The amount of points to around the window for drag resize direction calculations.
|
||||
const BORDER_SIZE: f64 = 20.;
|
||||
|
||||
@@ -94,20 +90,12 @@ struct Application {
|
||||
/// Drawing context.
|
||||
///
|
||||
/// With OpenGL it could be EGLDisplay.
|
||||
context: Option<Context<DisplayHandle<'static>>>,
|
||||
context: Context<OwnedDisplayHandle>,
|
||||
}
|
||||
|
||||
impl Application {
|
||||
fn new(event_loop: &EventLoop, receiver: Receiver<Action>, sender: Sender<Action>) -> Self {
|
||||
// SAFETY: we drop the context right before the event loop is stopped, thus making it safe.
|
||||
let context = Some(
|
||||
Context::new(unsafe {
|
||||
std::mem::transmute::<DisplayHandle<'_>, DisplayHandle<'static>>(
|
||||
event_loop.display_handle().unwrap(),
|
||||
)
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
let context = Context::new(event_loop.owned_display_handle()).unwrap();
|
||||
|
||||
// You'll have to choose an icon size at your own discretion. On X11, the desired size
|
||||
// varies by WM, and on Windows, you still have to account for screen scaling. Here
|
||||
@@ -596,9 +584,7 @@ impl ApplicationHandlerExtMacOS for Application {
|
||||
/// State of the window.
|
||||
struct WindowState {
|
||||
/// Render surface.
|
||||
///
|
||||
/// NOTE: This surface must be dropped before the `Window`.
|
||||
surface: Surface<DisplayHandle<'static>, Arc<dyn Window>>,
|
||||
surface: Surface<OwnedDisplayHandle, Arc<dyn Window>>,
|
||||
/// The actual winit Window.
|
||||
window: Arc<dyn Window>,
|
||||
/// The window theme we're drawing with.
|
||||
@@ -639,9 +625,7 @@ impl WindowState {
|
||||
fn new(app: &Application, window: Box<dyn Window>) -> Result<Self, Box<dyn Error>> {
|
||||
let window: Arc<dyn Window> = Arc::from(window);
|
||||
|
||||
// SAFETY: the surface is dropped before the `window` which provided it with handle, thus
|
||||
// it doesn't outlive it.
|
||||
let surface = Surface::new(app.context.as_ref().unwrap(), Arc::clone(&window))?;
|
||||
let surface = Surface::new(&app.context, Arc::clone(&window))?;
|
||||
|
||||
let theme = window.theme().unwrap_or(Theme::Dark);
|
||||
info!("Theme: {theme:?}");
|
||||
@@ -928,13 +912,17 @@ impl WindowState {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if self.animated_fill_color {
|
||||
fill::fill_window_with_animated_color(&*self.window, self.start_time);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut buffer = self.surface.buffer_mut()?;
|
||||
|
||||
if self.animated_fill_color {
|
||||
// Fill the entire buffer with a single color.
|
||||
let time = self.start_time.elapsed().as_secs_f32() * 1.5;
|
||||
let blue = (time.sin() * 255.0) as u32;
|
||||
let green = ((time.cos() * 255.0) as u32) << 8;
|
||||
let red = ((1.0 - time.sin() * 255.0) as u32) << 16;
|
||||
let color = red | green | blue;
|
||||
buffer.fill(color);
|
||||
} else {
|
||||
// Draw a different color inside the safe area
|
||||
let surface_size = self.window.surface_size();
|
||||
let insets = self.window.safe_area();
|
||||
@@ -960,6 +948,7 @@ impl WindowState {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Present the buffer
|
||||
self.window.pre_present_notify();
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
fn main() -> Result<(), impl std::error::Error> {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use softbuffer::{Context, Surface};
|
||||
use tracing::info;
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::dpi::{LogicalPosition, LogicalSize, Position};
|
||||
use winit::event::{ElementState, KeyEvent, WindowEvent};
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop, OwnedDisplayHandle};
|
||||
use winit::raw_window_handle::HasRawWindowHandle;
|
||||
use winit::window::{Window, WindowAttributes, WindowId};
|
||||
|
||||
@@ -16,18 +17,20 @@ fn main() -> Result<(), impl std::error::Error> {
|
||||
|
||||
#[derive(Debug)]
|
||||
struct WindowData {
|
||||
window: Box<dyn Window>,
|
||||
surface: Surface<OwnedDisplayHandle, Box<dyn Window>>,
|
||||
color: u32,
|
||||
}
|
||||
|
||||
impl WindowData {
|
||||
fn new(window: Box<dyn Window>, color: u32) -> Self {
|
||||
Self { window, color }
|
||||
fn new(context: &Context<OwnedDisplayHandle>, window: Box<dyn Window>, color: u32) -> Self {
|
||||
let surface = Surface::new(context, window).unwrap();
|
||||
Self { surface, color }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
#[derive(Debug)]
|
||||
struct Application {
|
||||
context: Context<OwnedDisplayHandle>,
|
||||
parent_window_id: Option<WindowId>,
|
||||
windows: HashMap<WindowId, WindowData>,
|
||||
}
|
||||
@@ -42,7 +45,7 @@ fn main() -> Result<(), impl std::error::Error> {
|
||||
info!("Parent window id: {:?})", window.id());
|
||||
self.parent_window_id = Some(window.id());
|
||||
|
||||
self.windows.insert(window.id(), WindowData::new(window, 0xffbbbbbb));
|
||||
self.windows.insert(window.id(), WindowData::new(&self.context, window, 0xffbbbbbb));
|
||||
}
|
||||
|
||||
fn window_event(
|
||||
@@ -73,18 +76,24 @@ fn main() -> Result<(), impl std::error::Error> {
|
||||
0xff000000 + 3_u32.pow((child_index + 2).rem_euclid(16) as u32);
|
||||
|
||||
let parent_window = self.windows.get(&self.parent_window_id.unwrap()).unwrap();
|
||||
let child_window =
|
||||
spawn_child_window(parent_window.window.as_ref(), event_loop, child_index);
|
||||
let child_window = spawn_child_window(
|
||||
parent_window.surface.window().as_ref(),
|
||||
event_loop,
|
||||
child_index,
|
||||
);
|
||||
let child_id = child_window.id();
|
||||
info!("Child window created with id: {child_id:?}");
|
||||
self.windows.insert(child_id, WindowData::new(child_window, child_color));
|
||||
self.windows.insert(
|
||||
child_id,
|
||||
WindowData::new(&self.context, child_window, child_color),
|
||||
);
|
||||
},
|
||||
WindowEvent::RedrawRequested => {
|
||||
if let Some(window) = self.windows.get(&window_id) {
|
||||
if let Some(window) = self.windows.get_mut(&window_id) {
|
||||
if window_id == self.parent_window_id.unwrap() {
|
||||
fill::fill_window(window.window.as_ref());
|
||||
fill::fill(&mut window.surface);
|
||||
} else {
|
||||
fill::fill_window_with_color(window.window.as_ref(), window.color);
|
||||
fill::fill_with_color(&mut window.surface, window.color);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -118,7 +127,8 @@ fn main() -> Result<(), impl std::error::Error> {
|
||||
}
|
||||
|
||||
let event_loop = EventLoop::new().unwrap();
|
||||
event_loop.run_app(Application::default())
|
||||
let context = Context::new(event_loop.owned_display_handle()).unwrap();
|
||||
event_loop.run_app(Application { context, parent_window_id: None, windows: HashMap::new() })
|
||||
}
|
||||
|
||||
#[cfg(not(any(x11_platform, macos_platform, windows_platform)))]
|
||||
|
||||
@@ -4,12 +4,13 @@ use std::thread;
|
||||
#[cfg(not(web_platform))]
|
||||
use std::time;
|
||||
|
||||
use softbuffer::{Context, Surface};
|
||||
use tracing::{info, warn};
|
||||
#[cfg(web_platform)]
|
||||
use web_time as time;
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::event::{ElementState, KeyEvent, StartCause, WindowEvent};
|
||||
use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
|
||||
use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop, OwnedDisplayHandle};
|
||||
use winit::keyboard::{Key, NamedKey};
|
||||
use winit::window::{Window, WindowAttributes, WindowId};
|
||||
|
||||
@@ -52,7 +53,7 @@ struct ControlFlowDemo {
|
||||
request_redraw: bool,
|
||||
wait_cancelled: bool,
|
||||
close_requested: bool,
|
||||
window: Option<Box<dyn Window>>,
|
||||
surface: Option<Surface<OwnedDisplayHandle, Box<dyn Window>>>,
|
||||
}
|
||||
|
||||
impl ApplicationHandler for ControlFlowDemo {
|
||||
@@ -69,7 +70,10 @@ impl ApplicationHandler for ControlFlowDemo {
|
||||
let window_attributes = WindowAttributes::default().with_title(
|
||||
"Press 1, 2, 3 to change control flow mode. Press R to toggle redraw requests.",
|
||||
);
|
||||
self.window = Some(event_loop.create_window(window_attributes).unwrap());
|
||||
let window = event_loop.create_window(window_attributes).unwrap();
|
||||
let context = Context::new(event_loop.owned_display_handle()).unwrap();
|
||||
let surface = Surface::new(&context, window).unwrap();
|
||||
self.surface = Some(surface);
|
||||
}
|
||||
|
||||
fn window_event(
|
||||
@@ -112,9 +116,9 @@ impl ApplicationHandler for ControlFlowDemo {
|
||||
_ => (),
|
||||
},
|
||||
WindowEvent::RedrawRequested => {
|
||||
let window = self.window.as_ref().unwrap();
|
||||
window.pre_present_notify();
|
||||
fill::fill_window(window.as_ref());
|
||||
let surface = self.surface.as_mut().unwrap();
|
||||
surface.window().pre_present_notify();
|
||||
fill::fill(surface);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
@@ -122,7 +126,7 @@ impl ApplicationHandler for ControlFlowDemo {
|
||||
|
||||
fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) {
|
||||
if self.request_redraw && !self.wait_cancelled && !self.close_requested {
|
||||
self.window.as_ref().unwrap().request_redraw();
|
||||
self.surface.as_ref().unwrap().window().request_redraw();
|
||||
}
|
||||
|
||||
match self.mode {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use std::error::Error;
|
||||
|
||||
use softbuffer::{Context, Surface};
|
||||
use tracing::info;
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::event::WindowEvent;
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop, OwnedDisplayHandle};
|
||||
use winit::window::{Window, WindowAttributes, WindowId};
|
||||
|
||||
#[path = "util/fill.rs"]
|
||||
@@ -16,27 +17,24 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
let event_loop = EventLoop::new()?;
|
||||
|
||||
let app = Application::new();
|
||||
let app = Application::default();
|
||||
Ok(event_loop.run_app(app)?)
|
||||
}
|
||||
|
||||
/// Application state and event handling.
|
||||
#[derive(Debug)]
|
||||
#[derive(Default, Debug)]
|
||||
struct Application {
|
||||
window: Option<Box<dyn Window>>,
|
||||
}
|
||||
|
||||
impl Application {
|
||||
fn new() -> Self {
|
||||
Self { window: None }
|
||||
}
|
||||
surface: Option<Surface<OwnedDisplayHandle, Box<dyn Window>>>,
|
||||
}
|
||||
|
||||
impl ApplicationHandler for Application {
|
||||
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
|
||||
let window_attributes =
|
||||
WindowAttributes::default().with_title("Drag and drop files on me!");
|
||||
self.window = Some(event_loop.create_window(window_attributes).unwrap());
|
||||
let window = event_loop.create_window(window_attributes).unwrap();
|
||||
let context = Context::new(event_loop.owned_display_handle()).unwrap();
|
||||
let surface = Surface::new(&context, window).unwrap();
|
||||
self.surface = Some(surface);
|
||||
}
|
||||
|
||||
fn window_event(
|
||||
@@ -53,9 +51,9 @@ impl ApplicationHandler for Application {
|
||||
info!("{event:?}");
|
||||
},
|
||||
WindowEvent::RedrawRequested => {
|
||||
let window = self.window.as_ref().unwrap();
|
||||
window.pre_present_notify();
|
||||
fill::fill_window(window.as_ref());
|
||||
let surface = self.surface.as_mut().unwrap();
|
||||
surface.window().pre_present_notify();
|
||||
fill::fill(surface);
|
||||
},
|
||||
WindowEvent::CloseRequested => {
|
||||
event_loop.exit();
|
||||
|
||||
@@ -9,10 +9,11 @@ use std::cmp;
|
||||
use std::error::Error;
|
||||
|
||||
use dpi::{LogicalPosition, PhysicalSize};
|
||||
use softbuffer::{Context, Surface};
|
||||
use tracing::{error, info};
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::event::{Ime, WindowEvent};
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop, OwnedDisplayHandle};
|
||||
use winit::keyboard::{Key, ModifiersState, NamedKey};
|
||||
#[cfg(web_platform)]
|
||||
use winit::platform::web::WindowAttributesWeb;
|
||||
@@ -30,7 +31,7 @@ const IME_CURSOR_SIZE: PhysicalSize<u32> = PhysicalSize::new(20, 20);
|
||||
|
||||
#[derive(Debug)]
|
||||
struct App {
|
||||
window: Option<Box<dyn Window>>,
|
||||
surface: Option<Surface<OwnedDisplayHandle, Box<dyn Window>>>,
|
||||
input_state: TextInputState,
|
||||
modifiers: ModifiersState,
|
||||
}
|
||||
@@ -73,14 +74,12 @@ impl ApplicationHandler for App {
|
||||
#[cfg(web_platform)]
|
||||
let window_attributes = WindowAttributes::default()
|
||||
.with_platform_attributes(Box::new(WindowAttributesWeb::default().with_append(true)));
|
||||
self.window = match event_loop.create_window(window_attributes) {
|
||||
Ok(window) => Some(window),
|
||||
Err(err) => {
|
||||
error!("error creating window: {err}");
|
||||
event_loop.exit();
|
||||
return;
|
||||
},
|
||||
};
|
||||
let window = event_loop.create_window(window_attributes).expect("failed creating window");
|
||||
|
||||
let context =
|
||||
Context::new(event_loop.owned_display_handle()).expect("failed creating context");
|
||||
let surface = Surface::new(&context, window).expect("failed creating surface");
|
||||
self.surface = Some(surface);
|
||||
|
||||
// Allow IME out of the box.
|
||||
let enable_request = ImeEnableRequest::new(
|
||||
@@ -101,11 +100,13 @@ impl ApplicationHandler for App {
|
||||
match event {
|
||||
WindowEvent::CloseRequested => {
|
||||
info!("Close was requested; stopping");
|
||||
self.window = None;
|
||||
self.surface = None;
|
||||
event_loop.exit();
|
||||
},
|
||||
WindowEvent::SurfaceResized(_) => {
|
||||
self.window.as_ref().expect("resize event without a window").request_redraw();
|
||||
WindowEvent::SurfaceResized(surface_size) => {
|
||||
let surface = self.surface.as_mut().expect("resize event without a surface");
|
||||
fill::resize(surface, surface_size);
|
||||
surface.window().request_redraw();
|
||||
},
|
||||
WindowEvent::RedrawRequested => {
|
||||
// Redraw the application.
|
||||
@@ -114,13 +115,13 @@ impl ApplicationHandler for App {
|
||||
// this event rather than in AboutToWait, since rendering in here allows
|
||||
// the program to gracefully handle redraws requested by the OS.
|
||||
|
||||
let window = self.window.as_ref().expect("redraw request without a window");
|
||||
let surface = self.surface.as_mut().expect("redraw event without a surface");
|
||||
|
||||
// Notify that you're about to draw.
|
||||
window.pre_present_notify();
|
||||
surface.window().pre_present_notify();
|
||||
|
||||
// Draw.
|
||||
fill::fill_window(window.as_ref());
|
||||
fill::fill(surface);
|
||||
|
||||
// For contiguous redraw loop you can request a redraw from here.
|
||||
// window.request_redraw();
|
||||
@@ -214,14 +215,14 @@ impl App {
|
||||
}
|
||||
|
||||
fn handle_ime_event(&mut self, event: Ime) {
|
||||
let window = self.window.as_ref().expect("IME request without a window");
|
||||
let surface = self.surface.as_ref().expect("IME request without a window");
|
||||
match event {
|
||||
Ime::Enabled => info!("IME enabled for Window={:?}", window.id()),
|
||||
Ime::Enabled => info!("IME enabled for Window={:?}", surface.window().id()),
|
||||
Ime::Preedit(text, caret_pos) => info!("Preedit: {text}, with caret at {caret_pos:?}"),
|
||||
Ime::Commit(text) => {
|
||||
self.input_state.append_text(&text);
|
||||
let request_data = self.get_ime_update();
|
||||
window.request_ime_update(ImeRequest::Update(request_data)).unwrap();
|
||||
surface.window().request_ime_update(ImeRequest::Update(request_data)).unwrap();
|
||||
self.print_input_state();
|
||||
},
|
||||
Ime::DeleteSurrounding { before_bytes, after_bytes } => {
|
||||
@@ -246,7 +247,7 @@ impl App {
|
||||
error!("Buggy IME tried to delete with indices not on char boundary.");
|
||||
}
|
||||
},
|
||||
Ime::Disabled => info!("IME disabled for Window={:?}", window.id()),
|
||||
Ime::Disabled => info!("IME disabled for Window={:?}", surface.window().id()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,7 +313,7 @@ impl App {
|
||||
}
|
||||
|
||||
fn window(&self) -> &dyn Window {
|
||||
self.window.as_ref().unwrap().as_ref()
|
||||
self.surface.as_ref().unwrap().window().as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,7 +356,7 @@ Use CTRL+h to cycle content hint permutations.
|
||||
);
|
||||
|
||||
let app = App {
|
||||
window: None,
|
||||
surface: None,
|
||||
input_state: TextInputState {
|
||||
ime_enabled: true,
|
||||
contents: String::new(),
|
||||
|
||||
@@ -7,11 +7,12 @@ fn main() -> std::process::ExitCode {
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
use softbuffer::{Context, Surface};
|
||||
use tracing::info;
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::event::WindowEvent;
|
||||
use winit::event_loop::pump_events::{EventLoopExtPumpEvents, PumpStatus};
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop, OwnedDisplayHandle};
|
||||
use winit::window::{Window, WindowAttributes, WindowId};
|
||||
|
||||
#[path = "util/fill.rs"]
|
||||
@@ -21,13 +22,16 @@ fn main() -> std::process::ExitCode {
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct PumpDemo {
|
||||
window: Option<Box<dyn Window>>,
|
||||
surface: Option<Surface<OwnedDisplayHandle, Box<dyn Window>>>,
|
||||
}
|
||||
|
||||
impl ApplicationHandler for PumpDemo {
|
||||
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
|
||||
let window_attributes = WindowAttributes::default().with_title("A fantastic window!");
|
||||
self.window = Some(event_loop.create_window(window_attributes).unwrap());
|
||||
let window = event_loop.create_window(window_attributes).unwrap();
|
||||
|
||||
let context = Context::new(event_loop.owned_display_handle()).unwrap();
|
||||
self.surface = Some(Surface::new(&context, window).unwrap());
|
||||
}
|
||||
|
||||
fn window_event(
|
||||
@@ -38,16 +42,16 @@ fn main() -> std::process::ExitCode {
|
||||
) {
|
||||
info!("{event:?}");
|
||||
|
||||
let window = match self.window.as_ref() {
|
||||
Some(window) => window,
|
||||
let surface = match self.surface.as_mut() {
|
||||
Some(surface) => surface,
|
||||
None => return,
|
||||
};
|
||||
|
||||
match event {
|
||||
WindowEvent::CloseRequested => event_loop.exit(),
|
||||
WindowEvent::RedrawRequested => {
|
||||
fill::fill_window(window.as_ref());
|
||||
window.request_redraw();
|
||||
fill::fill(surface);
|
||||
surface.window().request_redraw();
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
use std::time::Duration;
|
||||
|
||||
use softbuffer::{Context, Surface};
|
||||
use tracing::info;
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::event::WindowEvent;
|
||||
use winit::event_loop::run_on_demand::EventLoopExtRunOnDemand;
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop, OwnedDisplayHandle};
|
||||
use winit::window::{Window, WindowAttributes, WindowId};
|
||||
|
||||
#[path = "util/fill.rs"]
|
||||
@@ -17,27 +18,30 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
#[path = "util/tracing.rs"]
|
||||
mod tracing;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
#[derive(Debug)]
|
||||
struct App {
|
||||
context: Context<OwnedDisplayHandle>,
|
||||
idx: usize,
|
||||
surface: Option<Surface<OwnedDisplayHandle, Box<dyn Window>>>,
|
||||
window_id: Option<WindowId>,
|
||||
window: Option<Box<dyn Window>>,
|
||||
}
|
||||
|
||||
impl ApplicationHandler for App {
|
||||
fn about_to_wait(&mut self, _event_loop: &dyn ActiveEventLoop) {
|
||||
if let Some(window) = self.window.as_ref() {
|
||||
window.request_redraw();
|
||||
if let Some(surface) = self.surface.as_ref() {
|
||||
surface.window().request_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
|
||||
let window_attributes = WindowAttributes::default()
|
||||
.with_title("Fantastic window number one!")
|
||||
.with_title(format!("Fantastic window number {}!", self.idx))
|
||||
.with_surface_size(winit::dpi::LogicalSize::new(128.0, 128.0));
|
||||
let window = event_loop.create_window(window_attributes).unwrap();
|
||||
self.window_id = Some(window.id());
|
||||
self.window = Some(window);
|
||||
|
||||
let surface = Surface::new(&self.context, window).unwrap();
|
||||
self.surface = Some(surface);
|
||||
}
|
||||
|
||||
fn window_event(
|
||||
@@ -53,19 +57,17 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
return;
|
||||
}
|
||||
|
||||
let window = match self.window.as_mut() {
|
||||
Some(window) => window,
|
||||
None => return,
|
||||
let Some(surface) = self.surface.as_mut() else {
|
||||
return;
|
||||
};
|
||||
|
||||
match event {
|
||||
WindowEvent::CloseRequested => {
|
||||
info!("Window {} CloseRequested", self.idx);
|
||||
fill::cleanup_window(window.as_ref());
|
||||
self.window = None;
|
||||
self.surface = None;
|
||||
},
|
||||
WindowEvent::RedrawRequested => {
|
||||
fill::fill_window(window.as_ref());
|
||||
fill::fill(surface);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
@@ -76,7 +78,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
let mut event_loop = EventLoop::new().unwrap();
|
||||
|
||||
let mut app = App { idx: 1, ..Default::default() };
|
||||
let context = Context::new(event_loop.owned_display_handle()).unwrap();
|
||||
let mut app = App { context, idx: 1, surface: None, window_id: None };
|
||||
event_loop.run_app_on_demand(&mut app)?;
|
||||
|
||||
info!("Finished first loop");
|
||||
|
||||
@@ -1,115 +1,43 @@
|
||||
//! Fill the window buffer with a solid color.
|
||||
//!
|
||||
//! Launching a window without drawing to it has unpredictable results varying from platform to
|
||||
//! platform. In order to have well-defined examples, this module provides an easy way to
|
||||
//! fill the window buffer with a solid color.
|
||||
//!
|
||||
//! 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 std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::mem;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::num::NonZeroU32;
|
||||
#[cfg(not(web_platform))]
|
||||
use std::time::Instant;
|
||||
|
||||
use softbuffer::{Context, Surface};
|
||||
#[cfg(web_platform)]
|
||||
use web_time::Instant;
|
||||
use winit::window::{Window, WindowId};
|
||||
use rwh_06::{HasDisplayHandle, HasWindowHandle};
|
||||
use softbuffer::Surface;
|
||||
use winit::window::Window;
|
||||
|
||||
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.
|
||||
/// Resize the surface.
|
||||
pub fn resize(
|
||||
surface: &mut Surface<impl HasDisplayHandle, impl HasWindowHandle>,
|
||||
surface_size: dpi::PhysicalSize<u32>,
|
||||
) {
|
||||
// Handle zero-sized buffers.
|
||||
//
|
||||
// A static, thread-local map of graphics contexts to open windows.
|
||||
static GC: ManuallyDrop<RefCell<Option<GraphicsContext>>> = const { ManuallyDrop::new(RefCell::new(None)) };
|
||||
}
|
||||
|
||||
/// The graphics context used to draw to a window.
|
||||
struct GraphicsContext {
|
||||
/// The global softbuffer context.
|
||||
context: RefCell<Context<&'static dyn Window>>,
|
||||
|
||||
/// The hash map of window IDs to surfaces.
|
||||
surfaces: HashMap<WindowId, Surface<&'static dyn Window, &'static dyn Window>>,
|
||||
}
|
||||
|
||||
impl GraphicsContext {
|
||||
fn new(w: &dyn Window) -> Self {
|
||||
Self {
|
||||
context: RefCell::new(
|
||||
Context::new(unsafe { mem::transmute::<&'_ dyn Window, &'static dyn Window>(w) })
|
||||
.expect("Failed to create a softbuffer context"),
|
||||
),
|
||||
surfaces: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_surface(
|
||||
&mut self,
|
||||
window: &dyn Window,
|
||||
) -> &mut Surface<&'static dyn Window, &'static dyn Window> {
|
||||
self.surfaces.entry(window.id()).or_insert_with(|| {
|
||||
Surface::new(&self.context.borrow(), unsafe {
|
||||
mem::transmute::<&'_ dyn Window, &'static dyn Window>(window)
|
||||
})
|
||||
.expect("Failed to create a softbuffer surface")
|
||||
})
|
||||
}
|
||||
|
||||
fn destroy_surface(&mut self, window: &dyn Window) {
|
||||
self.surfaces.remove(&window.id());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fill_window_with_color(window: &dyn Window, color: u32) {
|
||||
GC.with(|gc| {
|
||||
let size = window.surface_size();
|
||||
// FIXME(madsmtm): This should be done by softbuffer internally in the future:
|
||||
// https://github.com/rust-windowing/softbuffer/issues/238
|
||||
let (Some(width), Some(height)) =
|
||||
(NonZeroU32::new(size.width), NonZeroU32::new(size.height))
|
||||
(NonZeroU32::new(surface_size.width), NonZeroU32::new(surface_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
|
||||
|
||||
surface.resize(width, height).expect("Failed to resize the softbuffer surface");
|
||||
}
|
||||
|
||||
/// Fill the window buffer with a solid color.
|
||||
pub fn fill_with_color(
|
||||
surface: &mut Surface<impl HasDisplayHandle, impl HasWindowHandle + AsRef<dyn Window>>,
|
||||
color: u32,
|
||||
) {
|
||||
let surface_size = surface.window().as_ref().surface_size();
|
||||
resize(surface, surface_size);
|
||||
|
||||
let mut buffer = surface.buffer_mut().expect("Failed to get the softbuffer buffer");
|
||||
buffer.fill(color);
|
||||
buffer.present().expect("Failed to present the softbuffer buffer");
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn fill_window(window: &dyn Window) {
|
||||
fill_window_with_color(window, 0xff181818);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn fill_window_with_animated_color(window: &dyn Window, start: Instant) {
|
||||
let time = start.elapsed().as_secs_f32() * 1.5;
|
||||
let blue = (time.sin() * 255.0) as u32;
|
||||
let green = ((time.cos() * 255.0) as u32) << 8;
|
||||
let red = ((1.0 - time.sin() * 255.0) as u32) << 16;
|
||||
let color = red | green | blue;
|
||||
fill_window_with_color(window, color);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn cleanup_window(window: &dyn Window) {
|
||||
GC.with(|gc| {
|
||||
let mut gc = gc.borrow_mut();
|
||||
if let Some(context) = gc.as_mut() {
|
||||
context.destroy_surface(window);
|
||||
}
|
||||
});
|
||||
pub fn fill(
|
||||
surface: &mut Surface<impl HasDisplayHandle, impl HasWindowHandle + AsRef<dyn Window>>,
|
||||
) {
|
||||
fill_with_color(surface, 0xff181818);
|
||||
}
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
use std::error::Error;
|
||||
|
||||
use tracing::{error, info};
|
||||
use softbuffer::{Context, Surface};
|
||||
use tracing::info;
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::event::WindowEvent;
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop, OwnedDisplayHandle};
|
||||
#[cfg(web_platform)]
|
||||
use winit::platform::web::WindowAttributesWeb;
|
||||
use winit::window::{Window, WindowAttributes, WindowId};
|
||||
@@ -17,7 +18,7 @@ mod tracing;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct App {
|
||||
window: Option<Box<dyn Window>>,
|
||||
surface: Option<Surface<OwnedDisplayHandle, Box<dyn Window>>>,
|
||||
}
|
||||
|
||||
impl ApplicationHandler for App {
|
||||
@@ -27,14 +28,12 @@ impl ApplicationHandler for App {
|
||||
#[cfg(web_platform)]
|
||||
let window_attributes = WindowAttributes::default()
|
||||
.with_platform_attributes(Box::new(WindowAttributesWeb::default().with_append(true)));
|
||||
self.window = match event_loop.create_window(window_attributes) {
|
||||
Ok(window) => Some(window),
|
||||
Err(err) => {
|
||||
error!("error creating window: {err}");
|
||||
event_loop.exit();
|
||||
return;
|
||||
},
|
||||
}
|
||||
let window = event_loop.create_window(window_attributes).expect("failed creating window");
|
||||
|
||||
let context =
|
||||
Context::new(event_loop.owned_display_handle()).expect("failed creating context");
|
||||
let surface = Surface::new(&context, window).expect("failed creating surface");
|
||||
self.surface = Some(surface);
|
||||
}
|
||||
|
||||
fn window_event(&mut self, event_loop: &dyn ActiveEventLoop, _: WindowId, event: WindowEvent) {
|
||||
@@ -44,8 +43,10 @@ impl ApplicationHandler for App {
|
||||
info!("Close was requested; stopping");
|
||||
event_loop.exit();
|
||||
},
|
||||
WindowEvent::SurfaceResized(_) => {
|
||||
self.window.as_ref().expect("resize event without a window").request_redraw();
|
||||
WindowEvent::SurfaceResized(surface_size) => {
|
||||
let surface = self.surface.as_mut().expect("resize event without a surface");
|
||||
fill::resize(surface, surface_size);
|
||||
surface.window().request_redraw();
|
||||
},
|
||||
WindowEvent::RedrawRequested => {
|
||||
// Redraw the application.
|
||||
@@ -54,13 +55,15 @@ impl ApplicationHandler for App {
|
||||
// this event rather than in AboutToWait, since rendering in here allows
|
||||
// the program to gracefully handle redraws requested by the OS.
|
||||
|
||||
let window = self.window.as_ref().expect("redraw request without a window");
|
||||
let surface = self.surface.as_mut().expect("redraw event without a surface");
|
||||
|
||||
// Notify that you're about to draw.
|
||||
window.pre_present_notify();
|
||||
surface.window().pre_present_notify();
|
||||
|
||||
// Draw.
|
||||
fill::fill_window(window.as_ref());
|
||||
let mut buffer = surface.buffer_mut().expect("Failed to get the softbuffer buffer");
|
||||
buffer.fill(0xff181818);
|
||||
buffer.present().expect("Failed to present the softbuffer buffer");
|
||||
|
||||
// For contiguous redraw loop you can request a redraw from here.
|
||||
// window.request_redraw();
|
||||
|
||||
@@ -3,9 +3,10 @@ use std::error::Error;
|
||||
|
||||
#[cfg(x11_platform)]
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
use softbuffer::{Context, Surface};
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::event::WindowEvent;
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||
use winit::event_loop::{ActiveEventLoop, EventLoop, OwnedDisplayHandle};
|
||||
use winit::platform::x11::WindowAttributesX11;
|
||||
use winit::window::{Window, WindowAttributes, WindowId};
|
||||
|
||||
@@ -17,7 +18,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
#[derive(Debug)]
|
||||
pub struct XEmbedDemo {
|
||||
parent_window_id: u32,
|
||||
window: Option<Box<dyn Window>>,
|
||||
surface: Option<Surface<OwnedDisplayHandle, Box<dyn Window>>>,
|
||||
}
|
||||
|
||||
impl ApplicationHandler for XEmbedDemo {
|
||||
@@ -29,7 +30,10 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
WindowAttributesX11::default().with_embed_parent_window(self.parent_window_id);
|
||||
window_attributes = window_attributes.with_platform_attributes(Box::new(x11_attrs));
|
||||
|
||||
self.window = Some(event_loop.create_window(window_attributes).unwrap());
|
||||
let window = event_loop.create_window(window_attributes).unwrap();
|
||||
let context = Context::new(event_loop.owned_display_handle()).unwrap();
|
||||
let surface = Surface::new(&context, window).unwrap();
|
||||
self.surface = Some(surface);
|
||||
}
|
||||
|
||||
fn window_event(
|
||||
@@ -38,19 +42,19 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
_window_id: WindowId,
|
||||
event: WindowEvent,
|
||||
) {
|
||||
let window = self.window.as_ref().unwrap();
|
||||
match event {
|
||||
WindowEvent::CloseRequested => event_loop.exit(),
|
||||
WindowEvent::RedrawRequested => {
|
||||
window.pre_present_notify();
|
||||
fill::fill_window(window.as_ref());
|
||||
let surface = self.surface.as_mut().unwrap();
|
||||
surface.window().pre_present_notify();
|
||||
fill::fill(surface);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn about_to_wait(&mut self, _event_loop: &dyn ActiveEventLoop) {
|
||||
self.window.as_ref().unwrap().request_redraw();
|
||||
self.surface.as_ref().unwrap().window().request_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +67,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
tracing::init();
|
||||
let event_loop = EventLoop::new()?;
|
||||
|
||||
Ok(event_loop.run_app(XEmbedDemo { parent_window_id, window: None })?)
|
||||
Ok(event_loop.run_app(XEmbedDemo { parent_window_id, surface: None })?)
|
||||
}
|
||||
|
||||
#[cfg(not(x11_platform))]
|
||||
|
||||
Reference in New Issue
Block a user