Skip to content

Commit 5dfdd54

Browse files
authored
Update to calloop 0.12.1 and wayland-rs 0.31.0
The update resolves the long present issue of event source not waking up during the concurrent reads due to not following the wayland's prepare_read protocol correctly. In particular, this let's downstream clients, like winit, to remove workarounds related to mesa doing blocking dispatch and winit missing wake ups due to that.
1 parent f9b1fef commit 5dfdd54

File tree

3 files changed

+352
-90
lines changed

3 files changed

+352
-90
lines changed

Cargo.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@ keywords = ["wayland", "windowing"]
1111
rust-version = "1.65.0"
1212

1313
[dependencies]
14-
wayland-client = "0.30.2"
15-
wayland-backend = "0.1.0"
16-
calloop = "0.10.0"
14+
wayland-client = "0.31.1"
15+
wayland-backend = "0.3.0"
16+
calloop = "0.12.1"
1717
log = { version = "0.4.19", optional = true }
1818
rustix = { version = "0.38.4", default-features = false, features = ["std"] }
19+
20+
[dev-dependencies]
21+
tempfile = "3.8.0"
22+
wayland-protocols = { version = "0.31.0", features = ["client"] }

examples/simplest-window.rs

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
use std::fs::File;
2+
use std::os::unix::prelude::AsFd;
3+
4+
use calloop::EventLoop;
5+
use calloop_wayland_source::WaylandSource;
6+
use wayland_client::protocol::{
7+
wl_buffer, wl_compositor, wl_keyboard, wl_registry, wl_seat, wl_shm, wl_shm_pool, wl_surface,
8+
};
9+
use wayland_client::{delegate_noop, Connection, Dispatch, QueueHandle, WEnum};
10+
11+
use wayland_protocols::xdg::shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base};
12+
13+
fn main() {
14+
let conn = Connection::connect_to_env().unwrap();
15+
16+
let event_queue = conn.new_event_queue();
17+
let qhandle = event_queue.handle();
18+
19+
let display = conn.display();
20+
display.get_registry(&qhandle, ());
21+
22+
let mut event_loop: EventLoop<State> =
23+
EventLoop::try_new().expect("Failed to initialize the event loop!");
24+
let loop_handle = event_loop.handle();
25+
WaylandSource::new(conn, event_queue).insert(loop_handle).unwrap();
26+
let stop_handle = event_loop.get_signal();
27+
28+
let mut state = State {
29+
running: true,
30+
base_surface: None,
31+
buffer: None,
32+
wm_base: None,
33+
xdg_surface: None,
34+
configured: false,
35+
stop_handle,
36+
};
37+
38+
println!("Starting the example window app, press <ESC> to quit.");
39+
40+
event_loop.run(None, &mut state, |_| {}).unwrap();
41+
}
42+
43+
struct State {
44+
running: bool,
45+
base_surface: Option<wl_surface::WlSurface>,
46+
buffer: Option<wl_buffer::WlBuffer>,
47+
wm_base: Option<xdg_wm_base::XdgWmBase>,
48+
xdg_surface: Option<(xdg_surface::XdgSurface, xdg_toplevel::XdgToplevel)>,
49+
configured: bool,
50+
stop_handle: calloop::LoopSignal,
51+
}
52+
53+
impl Dispatch<wl_registry::WlRegistry, ()> for State {
54+
fn event(
55+
state: &mut Self,
56+
registry: &wl_registry::WlRegistry,
57+
event: wl_registry::Event,
58+
_: &(),
59+
_: &Connection,
60+
qh: &QueueHandle<Self>,
61+
) {
62+
if let wl_registry::Event::Global { name, interface, .. } = event {
63+
match &interface[..] {
64+
"wl_compositor" => {
65+
let compositor =
66+
registry.bind::<wl_compositor::WlCompositor, _, _>(name, 1, qh, ());
67+
let surface = compositor.create_surface(qh, ());
68+
state.base_surface = Some(surface);
69+
70+
if state.wm_base.is_some() && state.xdg_surface.is_none() {
71+
state.init_xdg_surface(qh);
72+
}
73+
},
74+
"wl_shm" => {
75+
let shm = registry.bind::<wl_shm::WlShm, _, _>(name, 1, qh, ());
76+
77+
let (init_w, init_h) = (320, 240);
78+
79+
let mut file = tempfile::tempfile().unwrap();
80+
draw(&mut file, (init_w, init_h));
81+
let pool = shm.create_pool(file.as_fd(), (init_w * init_h * 4) as i32, qh, ());
82+
let buffer = pool.create_buffer(
83+
0,
84+
init_w as i32,
85+
init_h as i32,
86+
(init_w * 4) as i32,
87+
wl_shm::Format::Argb8888,
88+
qh,
89+
(),
90+
);
91+
state.buffer = Some(buffer.clone());
92+
93+
if state.configured {
94+
let surface = state.base_surface.as_ref().unwrap();
95+
surface.attach(Some(&buffer), 0, 0);
96+
surface.commit();
97+
}
98+
},
99+
"wl_seat" => {
100+
registry.bind::<wl_seat::WlSeat, _, _>(name, 1, qh, ());
101+
},
102+
"xdg_wm_base" => {
103+
let wm_base = registry.bind::<xdg_wm_base::XdgWmBase, _, _>(name, 1, qh, ());
104+
state.wm_base = Some(wm_base);
105+
106+
if state.base_surface.is_some() && state.xdg_surface.is_none() {
107+
state.init_xdg_surface(qh);
108+
}
109+
},
110+
_ => {},
111+
}
112+
}
113+
}
114+
}
115+
116+
// Ignore events from these object types in this example.
117+
delegate_noop!(State: ignore wl_compositor::WlCompositor);
118+
delegate_noop!(State: ignore wl_surface::WlSurface);
119+
delegate_noop!(State: ignore wl_shm::WlShm);
120+
delegate_noop!(State: ignore wl_shm_pool::WlShmPool);
121+
delegate_noop!(State: ignore wl_buffer::WlBuffer);
122+
123+
fn draw(tmp: &mut File, (buf_x, buf_y): (u32, u32)) {
124+
use std::cmp::min;
125+
use std::io::Write;
126+
let mut buf = std::io::BufWriter::new(tmp);
127+
for y in 0..buf_y {
128+
for x in 0..buf_x {
129+
let a = 0xFF;
130+
let r = min(((buf_x - x) * 0xFF) / buf_x, ((buf_y - y) * 0xFF) / buf_y);
131+
let g = min((x * 0xFF) / buf_x, ((buf_y - y) * 0xFF) / buf_y);
132+
let b = min(((buf_x - x) * 0xFF) / buf_x, (y * 0xFF) / buf_y);
133+
134+
let color = (a << 24) + (r << 16) + (g << 8) + b;
135+
buf.write_all(&color.to_ne_bytes()).unwrap();
136+
}
137+
}
138+
buf.flush().unwrap();
139+
}
140+
141+
impl State {
142+
fn init_xdg_surface(&mut self, qh: &QueueHandle<State>) {
143+
let wm_base = self.wm_base.as_ref().unwrap();
144+
let base_surface = self.base_surface.as_ref().unwrap();
145+
146+
let xdg_surface = wm_base.get_xdg_surface(base_surface, qh, ());
147+
let toplevel = xdg_surface.get_toplevel(qh, ());
148+
toplevel.set_title("A fantastic window!".into());
149+
150+
base_surface.commit();
151+
152+
self.xdg_surface = Some((xdg_surface, toplevel));
153+
}
154+
}
155+
156+
impl Dispatch<xdg_wm_base::XdgWmBase, ()> for State {
157+
fn event(
158+
_: &mut Self,
159+
wm_base: &xdg_wm_base::XdgWmBase,
160+
event: xdg_wm_base::Event,
161+
_: &(),
162+
_: &Connection,
163+
_: &QueueHandle<Self>,
164+
) {
165+
if let xdg_wm_base::Event::Ping { serial } = event {
166+
wm_base.pong(serial);
167+
}
168+
}
169+
}
170+
171+
impl Dispatch<xdg_surface::XdgSurface, ()> for State {
172+
fn event(
173+
state: &mut Self,
174+
xdg_surface: &xdg_surface::XdgSurface,
175+
event: xdg_surface::Event,
176+
_: &(),
177+
_: &Connection,
178+
_: &QueueHandle<Self>,
179+
) {
180+
if let xdg_surface::Event::Configure { serial, .. } = event {
181+
xdg_surface.ack_configure(serial);
182+
state.configured = true;
183+
let surface = state.base_surface.as_ref().unwrap();
184+
if let Some(ref buffer) = state.buffer {
185+
surface.attach(Some(buffer), 0, 0);
186+
surface.commit();
187+
}
188+
}
189+
}
190+
}
191+
192+
impl Dispatch<xdg_toplevel::XdgToplevel, ()> for State {
193+
fn event(
194+
state: &mut Self,
195+
_: &xdg_toplevel::XdgToplevel,
196+
event: xdg_toplevel::Event,
197+
_: &(),
198+
_: &Connection,
199+
_: &QueueHandle<Self>,
200+
) {
201+
if let xdg_toplevel::Event::Close {} = event {
202+
state.running = false;
203+
}
204+
}
205+
}
206+
207+
impl Dispatch<wl_seat::WlSeat, ()> for State {
208+
fn event(
209+
_: &mut Self,
210+
seat: &wl_seat::WlSeat,
211+
event: wl_seat::Event,
212+
_: &(),
213+
_: &Connection,
214+
qh: &QueueHandle<Self>,
215+
) {
216+
if let wl_seat::Event::Capabilities { capabilities: WEnum::Value(capabilities) } = event {
217+
if capabilities.contains(wl_seat::Capability::Keyboard) {
218+
seat.get_keyboard(qh, ());
219+
}
220+
}
221+
}
222+
}
223+
224+
impl Dispatch<wl_keyboard::WlKeyboard, ()> for State {
225+
fn event(
226+
state: &mut Self,
227+
_: &wl_keyboard::WlKeyboard,
228+
event: wl_keyboard::Event,
229+
_: &(),
230+
_: &Connection,
231+
_: &QueueHandle<Self>,
232+
) {
233+
if let wl_keyboard::Event::Key { key, .. } = event {
234+
if key == 1 {
235+
// ESC key
236+
state.stop_handle.stop();
237+
}
238+
}
239+
}
240+
}

0 commit comments

Comments
 (0)