basic wayland window

This commit is contained in:
stickynotememo
2025-11-19 16:36:43 +11:00
commit 6c8fc2b35f
4 changed files with 732 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
/target
Generated
+407
View File
@@ -0,0 +1,407 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "cc"
version = "1.2.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35900b6c8d709fb1d854671ae27aeaa9eec2f8b01b364e1619a40da3e6fe2afe"
dependencies = [
"find-msvc-tools",
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "downcast-rs"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "find-msvc-tools"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127"
[[package]]
name = "getrandom"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "libc"
version = "0.2.177"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
[[package]]
name = "linux-raw-sys"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
[[package]]
name = "memchr"
version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "memfile"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f64636fdb65a5f0740f920c4281f3dbb76a71e25e25914b6d27000739897d40e"
dependencies = [
"libc",
]
[[package]]
name = "memoffset"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
[[package]]
name = "nix"
version = "0.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c"
dependencies = [
"bitflags 1.3.2",
"cc",
"cfg-if",
"libc",
"memoffset",
]
[[package]]
name = "pkg-config"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quick-xml"
version = "0.37.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb"
dependencies = [
"memchr",
]
[[package]]
name = "quote"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "rustix"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
dependencies = [
"bitflags 2.10.0",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "shared_memory"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba8593196da75d9dc4f69349682bd4c2099f8cde114257d1ef7ef1b33d1aba54"
dependencies = [
"cfg-if",
"libc",
"nix",
"rand",
"win-sys",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "syn"
version = "2.0.110"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wayland-backend"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35"
dependencies = [
"cc",
"downcast-rs",
"rustix",
"smallvec",
"wayland-sys",
]
[[package]]
name = "wayland-client"
version = "0.31.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d"
dependencies = [
"bitflags 2.10.0",
"rustix",
"wayland-backend",
"wayland-scanner",
]
[[package]]
name = "wayland-protocols"
version = "0.32.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901"
dependencies = [
"bitflags 2.10.0",
"wayland-backend",
"wayland-client",
"wayland-scanner",
]
[[package]]
name = "wayland-scanner"
version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3"
dependencies = [
"proc-macro2",
"quick-xml",
"quote",
]
[[package]]
name = "wayland-sys"
version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142"
dependencies = [
"pkg-config",
]
[[package]]
name = "win-sys"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b7b128a98c1cfa201b09eb49ba285887deb3cbe7466a98850eb1adabb452be5"
dependencies = [
"windows",
]
[[package]]
name = "windows"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45296b64204227616fdbf2614cefa4c236b98ee64dfaaaa435207ed99fe7829f"
dependencies = [
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_msvc",
]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]]
name = "windows_aarch64_msvc"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d"
[[package]]
name = "windows_i686_gnu"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed"
[[package]]
name = "windows_i686_msvc"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956"
[[package]]
name = "windows_x86_64_gnu"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4"
[[package]]
name = "windows_x86_64_msvc"
version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9"
[[package]]
name = "wolf_render"
version = "0.1.0"
dependencies = [
"libc",
"memfile",
"shared_memory",
"wayland-client",
"wayland-protocols",
]
[[package]]
name = "zerocopy"
version = "0.8.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
+11
View File
@@ -0,0 +1,11 @@
[package]
name = "wolf_render"
version = "0.1.0"
edition = "2024"
[dependencies]
libc = "0.2.177"
memfile = "0.3.2"
shared_memory = "0.12.4"
wayland-client = "0.31"
wayland-protocols = { version = "0.32.9", features = ["client"] }
+313
View File
@@ -0,0 +1,313 @@
#![feature(more_qualified_paths)]
use std::time::Duration;
use std::{ffi::CString, thread::sleep};
use std::os::fd::BorrowedFd;
use wayland_client::{
Connection, Dispatch, EventQueue, Proxy, backend::ObjectId, delegate_noop, protocol::{
wl_buffer::{self, WlBuffer},
wl_compositor::{self, WlCompositor},
wl_registry, wl_shell,
wl_shm::{self, Format, WlShm},
wl_shm_pool::{self, WlShmPool},
wl_surface::{self, Event, WlSurface},
}
};
use libc::{O_CREAT, O_RDWR, PROT_READ, PROT_WRITE, S_IROTH, S_IRWXU, ftruncate, mmap, shm_open};
use wayland_protocols::xdg::{
self,
shell::client::{
xdg_surface::{self, XdgSurface},
xdg_toplevel::XdgToplevel,
xdg_wm_base::{self, XdgWmBase},
},
};
const WIDTH: i32 = 960;
const HEIGHT: i32 = 540;
#[derive(Debug)]
struct State {
exit: bool,
ready: bool,
compositor: Option<WlCompositor>,
surface: Option<WlSurface>,
shm: Option<WlShm>,
formats: Vec<Format>,
buffer: Option<WlBuffer>,
wm_base: Option<XdgWmBase>,
xdg_surface: Option<XdgSurface>,
toplevel_surface: Option<XdgToplevel>,
pool: Option<WlShmPool>,
}
impl Dispatch<wl_registry::WlRegistry, ()> for State {
fn event(
state: &mut Self,
proxy: &wl_registry::WlRegistry,
event: <wl_registry::WlRegistry as wayland_client::Proxy>::Event,
data: &(),
conn: &Connection,
qhandle: &wayland_client::QueueHandle<Self>,
) {
// Iterate over the globals given by the registry.
// Use the details from the global (name & version) to bind the proxy to the state
// variable, specifying which global is beiong bound in the turbofish of proxy.bind()
if let wl_registry::Event::Global {
name,
interface,
version,
} = event
{
match interface.as_str() {
"wl_compositor" => {
let compositor = proxy
.bind::<wl_compositor::WlCompositor, _, _>(name, version, qhandle, *data);
let surface = compositor.create_surface(qhandle, *data);
state.compositor = Some(compositor);
state.surface = Some(surface);
}
"wl_shm" => {
let shm = proxy.bind::<wl_shm::WlShm, _, _>(name, version, qhandle, *data);
state.shm = Some(shm);
}
"xdg_wm_base" => {
let wm_base =
proxy.bind::<xdg_wm_base::XdgWmBase, _, _>(name, version, qhandle, *data);
state.wm_base = Some(wm_base);
}
_ => {
// do nothing
}
};
}
}
}
impl Dispatch<WlShm, ()> for State {
fn event(
state: &mut Self,
proxy: &WlShm,
event: <WlShm as wayland_client::Proxy>::Event,
data: &(),
conn: &Connection,
qhandle: &wayland_client::QueueHandle<Self>,
) {
if let <WlShm as Proxy>::Event::Format { format } = event {
if let None = state.pool {
state.formats.push(
format
.into_result()
.expect("Couldn't understand format, or it was unknown"),
);
// Any wayland client must support Xrgb8888 and Argb8888
let channels: i32 = if state.formats.contains(&Format::Xrgb8888) {
4
} else {
4
}; // we know that the supported formats are only the two above, so we can safely assume that any format which is not Xrgb8888 is Argb8888, requiring 4 channels.
// FIX: 3 channels won't work, even with Xrgb8888 for some reason
// TODO: Update for more channels
let size: i32 = (WIDTH * HEIGHT * channels * 2).try_into().unwrap();
let name = CString::new("/wolf_renderer_buffer").expect("CString::new() failed"); // CString::new can only fail if a null byte is in the string. This string should never cause errors
let shm_fd = unsafe {
// SAFETY: We know that that at least a few megabytes of memory
// should be able to be allocated for the virtual buffer.
// Data races should not be possible as the compositor will
// not modify the buffer. (Non owners do not have write
// permissions)
let fildes = shm_open(name.as_ptr(), O_RDWR | O_CREAT, S_IRWXU | S_IROTH);
if fildes <= 0 {
panic!("Could not open SHM object. Error code: N/A") // TODO: implement errno reading
};
ftruncate(fildes, size.into());
BorrowedFd::borrow_raw(fildes)
};
let shm_pool = proxy.create_pool(shm_fd, size.try_into().unwrap(), qhandle, *data);
// TODO: Move drawing logic to event loop (double flush)
state.pool = Some(shm_pool);
};
} else {
unimplemented!()
}
}
}
impl Dispatch<WlBuffer, ()> for State {
fn event(
state: &mut Self,
proxy: &WlBuffer,
event: <WlBuffer as Proxy>::Event,
data: &(),
conn: &Connection,
qhandle: &wayland_client::QueueHandle<Self>,
) {
}
}
impl Dispatch<XdgWmBase, ()> for State {
fn event(
state: &mut Self,
proxy: &XdgWmBase,
event: <XdgWmBase as Proxy>::Event,
data: &(),
conn: &Connection,
qhandle: &wayland_client::QueueHandle<Self>,
) {
if let xdg_wm_base::Event::Ping { serial } = event {
state.wm_base.as_ref().unwrap().pong(serial); // Ok to unwrap as a ping won't be recieved until
// all the globals are bound (including xdg_wm_base)
// TODO: figure out as_ref
} else {
unreachable!();
};
}
}
impl Dispatch<XdgSurface, ()> for State {
fn event(
state: &mut Self,
proxy: &XdgSurface,
event: <XdgSurface as Proxy>::Event,
data: &(),
conn: &Connection,
qhandle: &wayland_client::QueueHandle<Self>,
) {
if let <XdgSurface as Proxy>::Event::Configure { serial } = event {
proxy.ack_configure(serial);
}
}
}
impl Dispatch<XdgToplevel, ()> for State {
fn event(
state: &mut Self,
proxy: &XdgToplevel,
event: <XdgToplevel as Proxy>::Event,
data: &(),
conn: &Connection,
qhandle: &wayland_client::QueueHandle<Self>,
) {
if let <XdgToplevel as Proxy>::Event::Configure {
width,
height,
states,
} = event
{
// state.xdg_surface.unwrap().ack_configure(serial);
// FIX: Figure out what serial I need for ack_configure with a toplevel
// xdg_surface
}
}
}
impl Dispatch<WlSurface, ()> for State {
fn event(
state: &mut Self,
proxy: &WlSurface,
event: <WlSurface as Proxy>::Event,
data: &(),
conn: &Connection,
qhandle: &wayland_client::QueueHandle<Self>,
) {
}
}
delegate_noop!(State: wl_shm_pool::WlShmPool);
delegate_noop!(State: wl_compositor::WlCompositor);
fn main() {
let Ok(conn) = Connection::connect_to_env() else {
panic!("Couldn't connect to Wayland environment");
};
let mut state = State {
exit: false,
ready: false,
compositor: None,
surface: None,
shm: None,
formats: vec![],
buffer: None,
wm_base: None,
xdg_surface: None,
toplevel_surface: None,
pool: None,
};
let mut event_queue: EventQueue<State> = conn.new_event_queue();
let display = conn.display();
let qh = &event_queue.handle();
display.get_registry(&qh, ());
while !state.exit {
event_queue.roundtrip(&mut state).unwrap();
event_queue.flush().expect("hopefully flushed"); // TODO: expect
// Assign roles to the surface as required, then attach the buffer, damage and commit
if let None = &state.toplevel_surface {
if let (Some(base), Some(surface), Some(buffer)) =
(&state.wm_base, &state.surface, &state.buffer)
{
// Buffer is required because it is to be attached to the surface.
let xdg_surface = base.get_xdg_surface(surface, qh, ()); // HACK: udata =/ ()
let toplevel_surface = xdg_surface.get_toplevel(qh, ()); // HACK: udata =/ ()
state.xdg_surface = Some(xdg_surface);
state.toplevel_surface = Some(toplevel_surface);
surface.attach(Some(buffer), 0, 0);
surface.damage(0, 0, WIDTH, HEIGHT);
surface.commit();
};
}
state.ready = if let (Some(_), Some(_), Some(_), Some(_), Some(_)) = (
&state.compositor,
&state.surface,
&state.shm,
&state.buffer,
&state.wm_base,
) {
true
} else {
false
};
if let Some(shm_pool) = &state.pool {
let channels: i32 = if state.formats.contains(&Format::Xrgb8888) {
4
} else {
4
}; // we know that the supported formats are only the two above, so we can safely assume that any format which is not Xrgb8888 is Argb8888, requiring 4 channels.
// FIX: 3 channels won't work, even with Xrgb8888 for some reason
// TODO: Update for more channels
let size: i32 = (WIDTH * HEIGHT * channels * 2).try_into().unwrap();
let buffer = shm_pool.create_buffer(
0,
WIDTH.try_into().unwrap(),
HEIGHT.try_into().unwrap(),
(WIDTH * channels).try_into().unwrap(),
if state.formats.contains(&Format::Xrgb8888) {
Format::Xrgb8888
} else {
Format::Argb8888
},
qh,
(),
);
state.buffer = Some(buffer.clone());
}
if state.ready {
dbg!("ready");
sleep(Duration::from_secs(2));
return;
};
}
}