Skip to content

Commit 9424f0b

Browse files
authored
Use polling crate for open_blocking on X11 (#264)
1 parent 20b7791 commit 9424f0b

5 files changed

Lines changed: 85 additions & 21 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ raw-window-handle = "0.5"
3838
[target.'cfg(target_os="linux")'.dependencies]
3939
x11rb = { version = "0.13.2", features = ["cursor", "resource_manager", "allow-unsafe-code", "dl-libxcb"], default-features = false }
4040
x11-dl = { version = "2.21" }
41-
nix = "0.22.0"
41+
polling = "3.11.0"
4242
percent-encoding = "2.3.1"
4343
bytemuck = "1.15.0"
4444

src/wrappers.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ pub mod xlib;
1919
#[cfg(all(target_os = "linux", feature = "opengl"))]
2020
pub mod glx;
2121

22+
#[cfg(target_os = "linux")]
23+
pub mod connection_poller;
24+
2225
/// Wrappers and utilities around the Win32 API
2326
#[cfg(target_os = "windows")]
2427
pub mod win32;

src/wrappers/connection_poller.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use polling::{Event, Events, Poller};
2+
use std::io;
3+
use std::os::fd::{AsFd, BorrowedFd};
4+
use std::time::Instant;
5+
6+
pub struct ConnectionPoller<'a> {
7+
poller: Poller,
8+
events: Events,
9+
fd: BorrowedFd<'a>,
10+
}
11+
12+
const CONNECTION_KEY: usize = 42;
13+
14+
impl<'a> ConnectionPoller<'a> {
15+
pub fn new(source: &'a impl AsFd) -> io::Result<Self> {
16+
let poller = Poller::new()?;
17+
let fd = source.as_fd();
18+
unsafe { poller.add(&fd, Event::readable(CONNECTION_KEY))? };
19+
20+
Ok(Self { poller, fd, events: Events::new() })
21+
}
22+
23+
pub fn wait(&mut self, deadline: Instant) -> io::Result<PollStatus> {
24+
self.events.clear();
25+
// NOTE: polling crate already handles retrying on EINTR
26+
let new_events_count = self.poller.wait_deadline(&mut self.events, deadline)?;
27+
28+
if new_events_count == 0 {
29+
return Ok(PollStatus::Nothing);
30+
}
31+
32+
for event in self.events.iter() {
33+
if event.key != CONNECTION_KEY {
34+
continue;
35+
}
36+
37+
if let Some(true) = event.is_err() {
38+
panic!("xcb connection poll error")
39+
}
40+
41+
if event.is_interrupt() {
42+
return Ok(PollStatus::ConnectionClosed);
43+
}
44+
45+
return Ok(PollStatus::ReadAvailable);
46+
}
47+
48+
Ok(PollStatus::Nothing)
49+
}
50+
51+
pub fn delete(self) -> io::Result<()> {
52+
self.poller.delete(self.fd)
53+
}
54+
}
55+
56+
impl<'a> Drop for ConnectionPoller<'a> {
57+
fn drop(&mut self) {
58+
let _ = self.poller.delete(self.fd);
59+
}
60+
}
61+
62+
pub enum PollStatus {
63+
Nothing,
64+
ReadAvailable,
65+
ConnectionClosed,
66+
}

src/wrappers/xlib/xlib_xcb.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::wrappers::xlib::xlib_connection::XlibConnection;
22
use std::error::Error;
33
use std::ops::Deref;
4+
use std::os::fd::{AsFd, BorrowedFd};
45
use std::os::raw::c_int;
56
use x11_dl::xlib::Display;
67
use x11_dl::xlib_xcb::Xlib_xcb;
@@ -72,3 +73,9 @@ impl Deref for XlibXcbConnection {
7273
&self.xcb_connection
7374
}
7475
}
76+
77+
impl AsFd for XlibXcbConnection {
78+
fn as_fd(&self) -> BorrowedFd<'_> {
79+
self.xcb_connection.as_fd()
80+
}
81+
}

src/x11/event_loop.rs

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::wrappers::connection_poller::{ConnectionPoller, PollStatus};
12
use crate::x11::drag_n_drop::DragNDropState;
23
use crate::x11::keyboard::{convert_key_press_event, convert_key_release_event, key_mods};
34
use crate::x11::{ParentHandle, Window, WindowInner};
@@ -6,7 +7,7 @@ use crate::{
67
WindowInfo,
78
};
89
use std::error::Error;
9-
use std::os::fd::AsRawFd;
10+
use std::rc::Rc;
1011
use std::time::{Duration, Instant};
1112
use x11rb::connection::Connection;
1213
use x11rb::protocol::Event as XEvent;
@@ -63,13 +64,9 @@ impl EventLoop {
6364
}
6465

6566
// Event loop
66-
// FIXME: poll() acts fine on linux, sometimes funky on *BSD. XCB upstream uses a define to
67-
// switch between poll() and select() (the latter of which is fine on *BSD), and we should do
68-
// the same.
6967
pub fn run(&mut self) -> Result<(), Box<dyn Error>> {
70-
use nix::poll::*;
71-
72-
let xcb_fd = self.window.xcb_connection.conn.as_raw_fd();
68+
let connection = Rc::clone(&self.window.xcb_connection);
69+
let mut poller = ConnectionPoller::new(&connection.conn)?;
7370

7471
let mut last_frame = Instant::now();
7572
self.event_loop_running = true;
@@ -87,24 +84,13 @@ impl EventLoop {
8784
last_frame = Instant::max(next_frame, Instant::now() - self.frame_interval);
8885
}
8986

90-
let mut fds = [PollFd::new(xcb_fd, PollFlags::POLLIN)];
91-
9287
// Check for any events in the internal buffers
9388
// before going to sleep:
9489
self.drain_xcb_events()?;
9590

9691
// FIXME: handle errors
97-
poll(&mut fds, next_frame.duration_since(Instant::now()).subsec_millis() as i32)
98-
.unwrap();
99-
100-
if let Some(revents) = fds[0].revents() {
101-
if revents.contains(PollFlags::POLLERR) {
102-
panic!("xcb connection poll error");
103-
}
104-
105-
if revents.contains(PollFlags::POLLIN) {
106-
self.drain_xcb_events()?;
107-
}
92+
if let PollStatus::ReadAvailable = poller.wait(next_frame).unwrap() {
93+
self.drain_xcb_events()?;
10894
}
10995

11096
// Check if the parents's handle was dropped (such as when the host
@@ -123,6 +109,8 @@ impl EventLoop {
123109
}
124110
}
125111

112+
poller.delete()?;
113+
126114
Ok(())
127115
}
128116

0 commit comments

Comments
 (0)