Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ raw-window-handle = "0.5"
[target.'cfg(target_os="linux")'.dependencies]
x11rb = { version = "0.13.2", features = ["cursor", "resource_manager", "allow-unsafe-code", "dl-libxcb"], default-features = false }
x11-dl = { version = "2.21" }
nix = "0.22.0"
polling = "3.11.0"
percent-encoding = "2.3.1"
bytemuck = "1.15.0"

Expand Down
3 changes: 3 additions & 0 deletions src/wrappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ pub mod xlib;
#[cfg(all(target_os = "linux", feature = "opengl"))]
pub mod glx;

#[cfg(target_os = "linux")]
pub mod connection_poller;

/// Wrappers and utilities around the Win32 API
#[cfg(target_os = "windows")]
pub mod win32;
Expand Down
66 changes: 66 additions & 0 deletions src/wrappers/connection_poller.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use polling::{Event, Events, Poller};
use std::io;
use std::os::fd::{AsFd, BorrowedFd};
use std::time::Instant;

pub struct ConnectionPoller<'a> {
poller: Poller,
events: Events,
fd: BorrowedFd<'a>,
}

const CONNECTION_KEY: usize = 42;

impl<'a> ConnectionPoller<'a> {
pub fn new(source: &'a impl AsFd) -> io::Result<Self> {
let poller = Poller::new()?;
let fd = source.as_fd();
unsafe { poller.add(&fd, Event::readable(CONNECTION_KEY))? };

Ok(Self { poller, fd, events: Events::new() })
}

pub fn wait(&mut self, deadline: Instant) -> io::Result<PollStatus> {
self.events.clear();
// NOTE: polling crate already handles retrying on EINTR
let new_events_count = self.poller.wait_deadline(&mut self.events, deadline)?;

if new_events_count == 0 {
return Ok(PollStatus::Nothing);
}

for event in self.events.iter() {
if event.key != CONNECTION_KEY {
continue;
}

if let Some(true) = event.is_err() {
panic!("xcb connection poll error")
}

if event.is_interrupt() {
return Ok(PollStatus::ConnectionClosed);
}

return Ok(PollStatus::ReadAvailable);
}

Ok(PollStatus::Nothing)
}

pub fn delete(self) -> io::Result<()> {
self.poller.delete(self.fd)
}
}

impl<'a> Drop for ConnectionPoller<'a> {
fn drop(&mut self) {
let _ = self.poller.delete(self.fd);
}
}

pub enum PollStatus {
Nothing,
ReadAvailable,
ConnectionClosed,
}
7 changes: 7 additions & 0 deletions src/wrappers/xlib/xlib_xcb.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::wrappers::xlib::xlib_connection::XlibConnection;
use std::error::Error;
use std::ops::Deref;
use std::os::fd::{AsFd, BorrowedFd};
use std::os::raw::c_int;
use x11_dl::xlib::Display;
use x11_dl::xlib_xcb::Xlib_xcb;
Expand Down Expand Up @@ -72,3 +73,9 @@ impl Deref for XlibXcbConnection {
&self.xcb_connection
}
}

impl AsFd for XlibXcbConnection {
fn as_fd(&self) -> BorrowedFd<'_> {
self.xcb_connection.as_fd()
}
}
28 changes: 8 additions & 20 deletions src/x11/event_loop.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::wrappers::connection_poller::{ConnectionPoller, PollStatus};
use crate::x11::drag_n_drop::DragNDropState;
use crate::x11::keyboard::{convert_key_press_event, convert_key_release_event, key_mods};
use crate::x11::{ParentHandle, Window, WindowInner};
Expand All @@ -6,7 +7,7 @@ use crate::{
WindowInfo,
};
use std::error::Error;
use std::os::fd::AsRawFd;
use std::rc::Rc;
use std::time::{Duration, Instant};
use x11rb::connection::Connection;
use x11rb::protocol::Event as XEvent;
Expand Down Expand Up @@ -63,13 +64,9 @@ impl EventLoop {
}

// Event loop
// FIXME: poll() acts fine on linux, sometimes funky on *BSD. XCB upstream uses a define to
// switch between poll() and select() (the latter of which is fine on *BSD), and we should do
// the same.
pub fn run(&mut self) -> Result<(), Box<dyn Error>> {
use nix::poll::*;

let xcb_fd = self.window.xcb_connection.conn.as_raw_fd();
let connection = Rc::clone(&self.window.xcb_connection);
let mut poller = ConnectionPoller::new(&connection.conn)?;

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

let mut fds = [PollFd::new(xcb_fd, PollFlags::POLLIN)];

// Check for any events in the internal buffers
// before going to sleep:
self.drain_xcb_events()?;

// FIXME: handle errors
poll(&mut fds, next_frame.duration_since(Instant::now()).subsec_millis() as i32)
.unwrap();

if let Some(revents) = fds[0].revents() {
if revents.contains(PollFlags::POLLERR) {
panic!("xcb connection poll error");
}

if revents.contains(PollFlags::POLLIN) {
self.drain_xcb_events()?;
}
if let PollStatus::ReadAvailable = poller.wait(next_frame).unwrap() {
self.drain_xcb_events()?;
}

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

poller.delete()?;

Ok(())
}

Expand Down
Loading