174 lines
5.0 KiB
Rust
174 lines
5.0 KiB
Rust
extern crate x11rb;
|
|
|
|
use x11rb::connection::Connection;
|
|
use x11rb::cursor::Handle as CursorHandle;
|
|
use x11rb::protocol::xproto::*;
|
|
use x11rb::protocol::Event;
|
|
use x11rb::resource_manager::new_from_default;
|
|
use x11rb::wrapper::ConnectionExt as _;
|
|
|
|
x11rb::atom_manager! {
|
|
pub Atoms: AtomsCookie {
|
|
WM_PROTOCOLS,
|
|
WM_DELETE_WINDOW,
|
|
_NET_WM_NAME,
|
|
UTF8_STRING,
|
|
}
|
|
}
|
|
|
|
fn init_tracing() {
|
|
use tracing_subscriber::prelude::*;
|
|
|
|
tracing_subscriber::registry()
|
|
.with(tracing_subscriber::fmt::layer())
|
|
.with(tracing_subscriber::EnvFilter::from_default_env())
|
|
.init();
|
|
}
|
|
|
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
init_tracing();
|
|
|
|
let (conn, screen_num) = x11rb::connect(None)?;
|
|
|
|
// The following is only needed for start_timeout_thread(), which is used for 'tests'
|
|
let conn1 = std::sync::Arc::new(conn);
|
|
let conn = &*conn1;
|
|
|
|
let screen = &conn.setup().roots[screen_num];
|
|
let win_id = conn.generate_id()?;
|
|
let gc_id = conn.generate_id()?;
|
|
let resource_db = new_from_default(conn)?;
|
|
let cursor_handle = CursorHandle::new(conn, screen_num, &resource_db)?;
|
|
|
|
let atoms = Atoms::new(conn)?.reply()?;
|
|
let cursor_handle = cursor_handle.reply()?;
|
|
|
|
let win_aux = CreateWindowAux::new()
|
|
.event_mask(EventMask::EXPOSURE | EventMask::STRUCTURE_NOTIFY | EventMask::NO_EVENT)
|
|
.background_pixel(screen.white_pixel)
|
|
.win_gravity(Gravity::NORTH_WEST)
|
|
// Just because, we set the cursor to "wait"
|
|
.cursor(cursor_handle.load_cursor(conn, "wait")?);
|
|
|
|
let gc_aux = CreateGCAux::new().foreground(screen.black_pixel);
|
|
|
|
let (mut width, mut height) = (100, 100);
|
|
|
|
conn.create_window(
|
|
screen.root_depth,
|
|
win_id,
|
|
screen.root,
|
|
0,
|
|
0,
|
|
width,
|
|
height,
|
|
0,
|
|
WindowClass::INPUT_OUTPUT,
|
|
0,
|
|
&win_aux,
|
|
)?;
|
|
|
|
util::start_timeout_thread(conn1.clone(), win_id);
|
|
|
|
let title = "Simple Window";
|
|
conn.change_property8(
|
|
PropMode::REPLACE,
|
|
win_id,
|
|
AtomEnum::WM_NAME,
|
|
AtomEnum::STRING,
|
|
title.as_bytes(),
|
|
)?;
|
|
conn.change_property8(
|
|
PropMode::REPLACE,
|
|
win_id,
|
|
atoms._NET_WM_NAME,
|
|
atoms.UTF8_STRING,
|
|
title.as_bytes(),
|
|
)?;
|
|
conn.change_property32(
|
|
PropMode::REPLACE,
|
|
win_id,
|
|
atoms.WM_PROTOCOLS,
|
|
AtomEnum::ATOM,
|
|
&[atoms.WM_DELETE_WINDOW],
|
|
)?;
|
|
conn.change_property8(
|
|
PropMode::REPLACE,
|
|
win_id,
|
|
AtomEnum::WM_CLASS,
|
|
AtomEnum::STRING,
|
|
b"simple_window\0simple_window\0",
|
|
)?;
|
|
conn.change_property8(
|
|
PropMode::REPLACE,
|
|
win_id,
|
|
AtomEnum::WM_CLIENT_MACHINE,
|
|
AtomEnum::STRING,
|
|
// Text encoding in X11 is complicated. Let's use UTF-8 and hope for the best.
|
|
gethostname::gethostname()
|
|
.to_str()
|
|
.unwrap_or("[Invalid]")
|
|
.as_bytes(),
|
|
)?;
|
|
|
|
let reply = conn
|
|
.get_property(false, win_id, AtomEnum::WM_NAME, AtomEnum::STRING, 0, 1024)?
|
|
.reply()?;
|
|
assert_eq!(reply.value, title.as_bytes());
|
|
|
|
conn.create_gc(gc_id, win_id, &gc_aux)?;
|
|
|
|
conn.map_window(win_id)?;
|
|
|
|
conn.flush()?;
|
|
|
|
loop {
|
|
let event = conn.wait_for_event()?;
|
|
tracing::debug!("Got event {event:?}");
|
|
match event {
|
|
Event::Expose(event) => {
|
|
if event.count == 0 {
|
|
// There already is a white background because we set background_pixel to white
|
|
// when creating the window.
|
|
let (width, height): (i16, i16) = (width as _, height as _);
|
|
let points = [
|
|
Point {
|
|
x: width,
|
|
y: height,
|
|
},
|
|
Point { x: -10, y: -10 },
|
|
Point {
|
|
x: -10,
|
|
y: height + 10,
|
|
},
|
|
Point {
|
|
x: width + 10,
|
|
y: -10,
|
|
},
|
|
];
|
|
conn.poly_line(CoordMode::ORIGIN, win_id, gc_id, &points)?;
|
|
conn.flush()?;
|
|
}
|
|
}
|
|
Event::ConfigureNotify(event) => {
|
|
width = event.width;
|
|
height = event.height;
|
|
}
|
|
Event::ClientMessage(event) => {
|
|
let data = event.data.as_data32();
|
|
if event.format == 32 && event.window == win_id && data[0] == atoms.WM_DELETE_WINDOW
|
|
{
|
|
tracing::info!("Window was asked to close");
|
|
return Ok(());
|
|
}
|
|
}
|
|
Event::Error(err) => {
|
|
tracing::error!("Got an unexpected error: {err:?}")
|
|
}
|
|
event => tracing::info!("Got an unhandled event: {event:?}"),
|
|
}
|
|
}
|
|
}
|
|
|
|
include!("integration_test_util/util.rs");
|