Skip to content

Commit 87ce769

Browse files
authored
fix: Fix winit examples window not showing up under Wayland (#625)
1 parent 9e07b15 commit 87ce769

File tree

5 files changed

+204
-4
lines changed

5 files changed

+204
-4
lines changed

Cargo.lock

Lines changed: 54 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

platforms/winit/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,10 @@ version = "0.30.5"
4141
default-features = false
4242
features = ["x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"]
4343

44+
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dev-dependencies]
45+
softbuffer = { version = "0.4.0", default-features = false, features = [
46+
"x11",
47+
"x11-dlopen",
48+
"wayland",
49+
"wayland-dlopen",
50+
] }

platforms/winit/examples/mixed_handlers.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#[path = "util/fill.rs"]
2+
mod fill;
3+
14
use accesskit::{
25
Action, ActionRequest, ActivationHandler, Live, Node, NodeId, Rect, Role, Tree, TreeUpdate,
36
};
@@ -205,8 +208,12 @@ impl ApplicationHandler<AccessKitEvent> for Application {
205208
adapter.process_event(&window.window, &event);
206209
match event {
207210
WindowEvent::CloseRequested => {
211+
fill::cleanup_window(&window.window);
208212
self.window = None;
209213
}
214+
WindowEvent::RedrawRequested => {
215+
fill::fill_window(&window.window);
216+
}
210217
WindowEvent::KeyboardInput {
211218
event:
212219
KeyEvent {
@@ -270,7 +277,9 @@ impl ApplicationHandler<AccessKitEvent> for Application {
270277
}
271278

272279
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
273-
if self.window.is_none() {
280+
if let Some(window) = self.window.as_ref() {
281+
window.window.request_redraw();
282+
} else {
274283
event_loop.exit();
275284
}
276285
}

platforms/winit/examples/simple.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#[path = "util/fill.rs"]
2+
mod fill;
3+
14
use accesskit::{Action, ActionRequest, Live, Node, NodeId, Rect, Role, Tree, TreeUpdate};
25
use accesskit_winit::{Adapter, Event as AccessKitEvent, WindowEvent as AccessKitWindowEvent};
36
use std::error::Error;
@@ -182,8 +185,12 @@ impl ApplicationHandler<AccessKitEvent> for Application {
182185
adapter.process_event(&window.window, &event);
183186
match event {
184187
WindowEvent::CloseRequested => {
188+
fill::cleanup_window(&window.window);
185189
self.window = None;
186190
}
191+
WindowEvent::RedrawRequested => {
192+
fill::fill_window(&window.window);
193+
}
187194
WindowEvent::KeyboardInput {
188195
event:
189196
KeyEvent {
@@ -246,7 +253,9 @@ impl ApplicationHandler<AccessKitEvent> for Application {
246253
}
247254

248255
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
249-
if self.window.is_none() {
256+
if let Some(window) = self.window.as_ref() {
257+
window.window.request_redraw();
258+
} else {
250259
event_loop.exit();
251260
}
252261
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// Adapted from winit's examples/util/fill.rs.
2+
3+
//! Fill the window buffer with a solid color.
4+
//!
5+
//! Launching a window without drawing to it has unpredictable results varying from platform to
6+
//! platform. In order to have well-defined examples, this module provides an easy way to
7+
//! fill the window buffer with a solid color.
8+
//!
9+
//! The `softbuffer` crate is used, largely because of its ease of use. `glutin` or `wgpu` could
10+
//! also be used to fill the window buffer, but they are more complicated to use.
11+
12+
pub use platform::cleanup_window;
13+
pub use platform::fill_window;
14+
15+
#[cfg(not(any(target_os = "android", target_os = "ios")))]
16+
mod platform {
17+
use std::cell::RefCell;
18+
use std::collections::HashMap;
19+
use std::mem;
20+
use std::mem::ManuallyDrop;
21+
use std::num::NonZeroU32;
22+
23+
use softbuffer::{Context, Surface};
24+
use winit::window::{Window, WindowId};
25+
26+
thread_local! {
27+
// NOTE: You should never do things like that, create context and drop it before
28+
// you drop the event loop. We do this for brevity to not blow up examples. We use
29+
// ManuallyDrop to prevent destructors from running.
30+
//
31+
// A static, thread-local map of graphics contexts to open windows.
32+
static GC: ManuallyDrop<RefCell<Option<GraphicsContext>>> = const { ManuallyDrop::new(RefCell::new(None)) };
33+
}
34+
35+
/// The graphics context used to draw to a window.
36+
struct GraphicsContext {
37+
/// The global softbuffer context.
38+
context: RefCell<Context<&'static Window>>,
39+
40+
/// The hash map of window IDs to surfaces.
41+
surfaces: HashMap<WindowId, Surface<&'static Window, &'static Window>>,
42+
}
43+
44+
impl GraphicsContext {
45+
fn new(w: &Window) -> Self {
46+
Self {
47+
context: RefCell::new(
48+
Context::new(unsafe { mem::transmute::<&'_ Window, &'static Window>(w) })
49+
.expect("Failed to create a softbuffer context"),
50+
),
51+
surfaces: HashMap::new(),
52+
}
53+
}
54+
55+
fn create_surface(
56+
&mut self,
57+
window: &Window,
58+
) -> &mut Surface<&'static Window, &'static Window> {
59+
self.surfaces.entry(window.id()).or_insert_with(|| {
60+
Surface::new(&self.context.borrow(), unsafe {
61+
mem::transmute::<&'_ Window, &'static Window>(window)
62+
})
63+
.expect("Failed to create a softbuffer surface")
64+
})
65+
}
66+
67+
fn destroy_surface(&mut self, window: &Window) {
68+
self.surfaces.remove(&window.id());
69+
}
70+
}
71+
72+
pub fn fill_window(window: &Window) {
73+
GC.with(|gc| {
74+
let size = window.inner_size();
75+
let (Some(width), Some(height)) =
76+
(NonZeroU32::new(size.width), NonZeroU32::new(size.height))
77+
else {
78+
return;
79+
};
80+
81+
// Either get the last context used or create a new one.
82+
let mut gc = gc.borrow_mut();
83+
let surface = gc
84+
.get_or_insert_with(|| GraphicsContext::new(window))
85+
.create_surface(window);
86+
87+
// Fill a buffer with a solid color.
88+
const DARK_GRAY: u32 = 0xff181818;
89+
90+
surface
91+
.resize(width, height)
92+
.expect("Failed to resize the softbuffer surface");
93+
94+
let mut buffer = surface
95+
.buffer_mut()
96+
.expect("Failed to get the softbuffer buffer");
97+
buffer.fill(DARK_GRAY);
98+
buffer
99+
.present()
100+
.expect("Failed to present the softbuffer buffer");
101+
})
102+
}
103+
104+
pub fn cleanup_window(window: &Window) {
105+
GC.with(|gc| {
106+
let mut gc = gc.borrow_mut();
107+
if let Some(context) = gc.as_mut() {
108+
context.destroy_surface(window);
109+
}
110+
});
111+
}
112+
}
113+
114+
#[cfg(any(target_os = "android", target_os = "ios"))]
115+
mod platform {
116+
pub fn fill_window(_window: &winit::window::Window) {
117+
// No-op on mobile platforms.
118+
}
119+
120+
pub fn cleanup_window(_window: &winit::window::Window) {
121+
// No-op on mobile platforms.
122+
}
123+
}

0 commit comments

Comments
 (0)