Skip to content

Commit

Permalink
Merge pull request #797 from psychon/notgull/async-rc
Browse files Browse the repository at this point in the history
feat: Add a pure-Rust connection to x11rb-async
  • Loading branch information
mergify[bot] authored Mar 22, 2023
2 parents 62fd6fa + 0ff7602 commit 236a355
Show file tree
Hide file tree
Showing 6 changed files with 1,628 additions and 62 deletions.
3 changes: 3 additions & 0 deletions x11rb-async/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ license = "MIT OR Apache-2.0"
keywords = ["xcb", "x11", "async"]

[dependencies]
async-io = "1.12.0"
async-lock = "2.7.0"
blocking = "1.3.0"
event-listener = "2.5.3"
futures-lite = "1"
x11rb = { version = "0.11.1", path = "../x11rb", default-features = false }
x11rb-protocol = { version = "0.11.1", path = "../x11rb-protocol" }
Expand Down
125 changes: 63 additions & 62 deletions x11rb-async/examples/xclock_utc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@ use std::cell::RefCell;
use std::env;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

use x11rb::rust_connection::RustConnection;

use x11rb_async::blocking::BlockingConnection;
use x11rb_async::connection::Connection;
use x11rb_async::errors::{ConnectionError, ReplyOrIdError};
use x11rb_async::protocol::{xproto::*, Event};
use x11rb_async::rust_connection::RustConnection;

struct Atoms {
utf8_string: Atom,
Expand Down Expand Up @@ -223,77 +221,80 @@ async fn redraw(
}

async fn main2() -> Result<(), Box<dyn std::error::Error>> {
// Open a new connection.
let (conn, screen_index) = BlockingConnection::<RustConnection>::connect(None).await?;

// Setup atoms for this connection.
let atoms = Atoms::load(&conn).await?;
let screen = conn.setup().roots.get(screen_index).unwrap();

// Create a window.
let (width, height) = (100, 100);
let window = create_window(&conn, screen, &atoms, (width, height)).await?;

// Create a graphics context.
let gc_id = conn.generate_id().await?;
conn.create_gc(gc_id, window, &CreateGCAux::new()).await?;

// This is shared between tasks.
let (width, height) = (100, 100);
let size = RefCell::new((width, height));

// Open a new connection.
let (conn, screen_index, drive) = RustConnection::connect(None).await?;
let screen = conn.setup().roots.get(screen_index).unwrap();

// Create an executor for spawning tasks.
let ex = LocalExecutor::new();

// On X11RB_EXAMPLE_TIMEOUT, exit after a set timeout.
if let Some(timeout) = env::var("X11RB_EXAMPLE_TIMEOUT")
.ok()
.and_then(|s| s.parse().ok())
{
ex.spawn(async move {
Timer::after(Duration::from_secs(timeout)).await;
std::process::exit(0);
})
.detach();
}

// Span a task that redraws the window every second.
ex.spawn({
let conn = &conn;
ex.run({
let ex = &ex;
let size = &size;
let conn = &conn;

async move {
// Create a timer that fires every second.
let timer = Timer::interval(Duration::from_millis(1_000));

// Iterate over this timer endlessly.
timer
.then(move |_| async move {
// Redraw after one second has passed.
let (width, height) = *size.borrow();
redraw(conn, screen, window, gc_id, (width, height)).await?;
conn.flush().await?;

Ok::<_, ConnectionError>(())
})
.for_each(|res| {
if let Err(e) = res {
eprintln!("Timer task failed: {}", e);
}
// Spawn a task to poll for events.
ex.spawn(async move {
if let Err(e) = drive.await {
eprintln!("Error while driving the connection: {}", e);
}
})
.detach();

// Setup atoms for this connection.
let atoms = Atoms::load(conn).await?;

// Create a window.
let window = create_window(conn, screen, &atoms, (width, height)).await?;

// Create a graphics context.
let gc_id = conn.generate_id().await?;
conn.create_gc(gc_id, window, &CreateGCAux::new()).await?;

// On X11RB_EXAMPLE_TIMEOUT, exit after a set timeout.
if let Some(timeout) = env::var("X11RB_EXAMPLE_TIMEOUT")
.ok()
.and_then(|s| s.parse().ok())
{
ex.spawn(async move {
Timer::after(Duration::from_secs(timeout)).await;
std::process::exit(0);
})
.await;
}
})
.detach();
.detach();
}

// Flush the connection so far.
conn.flush().await?;
// Span a task that redraws the window every second.
ex.spawn(async move {
// Create a timer that fires every second.
let timer = Timer::interval(Duration::from_millis(1_000));

// Iterate over this timer endlessly.
timer
.then(move |_| async move {
// Redraw after one second has passed.
let (width, height) = *size.borrow();
redraw(conn, screen, window, gc_id, (width, height)).await?;
conn.flush().await?;

Ok::<_, ConnectionError>(())
})
.for_each(|res| {
if let Err(e) = res {
eprintln!("Timer task failed: {}", e);
}
})
.await;
})
.detach();

// Run the executor to drive the loop.
ex.run({
let conn = &conn;
let size = &size;
// Flush the connection so far.
conn.flush().await?;

async move {
loop {
// Get the next event.
let event = conn.wait_for_event().await?;
Expand All @@ -314,7 +315,7 @@ async fn main2() -> Result<(), Box<dyn std::error::Error>> {
&& data[0] == atoms.wm_delete_window
{
println!("Window was asked to close");
return Ok::<_, ConnectionError>(());
return Ok::<_, Box<dyn std::error::Error>>(());
}
}

Expand Down
1 change: 1 addition & 0 deletions x11rb-async/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod connection;
#[allow(clippy::type_complexity)]
#[rustfmt::skip]
pub mod protocol;
pub mod rust_connection;

#[doc(inline)]
pub use x11rb::{errors, x11_utils};
Expand Down
Loading

0 comments on commit 236a355

Please sign in to comment.