commit cbd1283e89b5a33e9d99de9db907d59e8e717844 Author: TQ Hirsch Date: Mon May 2 17:46:39 2022 +0200 Initial commit; mostly a clone of an example from smithay_client_toolkit diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..051d09d --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +eval "$(lorri direnv)" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..db36527 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +*~ +.idea diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..a61e05e --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,321 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "calloop" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf2eec61efe56aa1e813f5126959296933cf0700030e4314786c48779a66ab82" +dependencies = [ + "log", + "nix", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "dlib" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" +dependencies = [ + "libloading", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" + +[[package]] +name = "libloading" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "log" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memmap2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b6c2ebff6180198788f5db08d7ce3bc1d0b617176678831a7510825973e357" +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 = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nix" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "memoffset", +] + +[[package]] +name = "nom" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "once_cell" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" + +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "proc-macro2" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "smithay-client-toolkit" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a28f16a97fa0e8ce563b2774d1e732dd5d4025d2772c5dba0a41a0f90a29da3" +dependencies = [ + "bitflags", + "calloop", + "dlib", + "lazy_static", + "log", + "memmap2", + "nix", + "pkg-config", + "wayland-client", + "wayland-cursor", + "wayland-protocols", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "wattbar" +version = "0.1.0" +dependencies = [ + "anyhow", + "calloop", + "smithay-client-toolkit", + "wayland-client", + "wayland-protocols", +] + +[[package]] +name = "wayland-client" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91223460e73257f697d9e23d401279123d36039a3f7a449e983f123292d4458f" +dependencies = [ + "bitflags", + "downcast-rs", + "libc", + "nix", + "wayland-commons", + "wayland-scanner", + "wayland-sys", +] + +[[package]] +name = "wayland-commons" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f6e5e340d7c13490eca867898c4cec5af56c27a5ffe5c80c6fc4708e22d33e" +dependencies = [ + "nix", + "once_cell", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-cursor" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c52758f13d5e7861fc83d942d3d99bf270c83269575e52ac29e5b73cb956a6bd" +dependencies = [ + "nix", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60147ae23303402e41fe034f74fb2c35ad0780ee88a1c40ac09a3be1e7465741" +dependencies = [ + "bitflags", + "wayland-client", + "wayland-commons", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a1ed3143f7a143187156a2ab52742e89dac33245ba505c17224df48939f9e0" +dependencies = [ + "proc-macro2", + "quote", + "xml-rs", +] + +[[package]] +name = "wayland-sys" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9341df79a8975679188e37dab3889bfa57c44ac2cb6da166f519a81cbe452d4" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "xcursor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" +dependencies = [ + "nom", +] + +[[package]] +name = "xml-rs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0c64071 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "wattbar" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +wayland-client = "0.29" +wayland-protocols = "0.29" +anyhow = "1" +smithay-client-toolkit = { version = "0.15", default-features = false, features = ["calloop"] } +calloop = "0.9.3" \ No newline at end of file diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..6bb4e70 --- /dev/null +++ b/shell.nix @@ -0,0 +1,13 @@ +{ pkgs ? import {} }: + +pkgs.mkShell { + buildInputs = with pkgs; [ + libxkbcommon + # keep this line if you use bash + bashInteractive + ]; + + nativeBuildInputs = with pkgs; [ + pkg-config + ]; +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..965811a --- /dev/null +++ b/src/main.rs @@ -0,0 +1,200 @@ + +use std::{ + cell::RefCell, + rc::Rc, +}; +use std::cell::Cell; +use wayland_client::{Attached, Main, protocol::{ + wl_shm, + wl_surface::WlSurface, + wl_output::WlOutput, +}}; + +use wayland_protocols::wlr::unstable::layer_shell::v1::client::{ + zwlr_layer_surface_v1::{self, ZwlrLayerSurfaceV1}, + zwlr_layer_shell_v1::{self, ZwlrLayerShellV1}, +}; + +use smithay_client_toolkit::{ + default_environment, + new_default_environment, + environment::SimpleGlobal, + output::OutputInfo, + WaylandSource, + output::with_output_info, + shm::AutoMemPool +}; + + +default_environment!{ + MyEnv, + fields = [ + layer_shell: SimpleGlobal, + ], + singles = [ + ZwlrLayerShellV1 => layer_shell, + ], +} + +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +pub enum RenderEvent { + Closed, + Configure { + width: u32, + height: u32, + } +} + +pub struct Surface { + surface: WlSurface, + layer_surface: Main, + next_render_event: Rc>>, + pool: AutoMemPool, + dimensions: (u32, u32), +} + +impl Surface { + fn new( + output: &WlOutput, + surface: WlSurface, + layer_shell: &Attached, + pool: AutoMemPool, + ) -> Self { + let layer_surface: Main = layer_shell.get_layer_surface( + &surface, + Some(output), + zwlr_layer_shell_v1::Layer::Bottom, + "WattBar".to_owned(), + ); + + layer_surface.set_size(32, 32); + layer_surface.set_anchor(zwlr_layer_surface_v1::Anchor::Bottom); + layer_surface.set_exclusive_zone(3); + let next_render_event = Rc::new(Cell::new(None)); + let nre_handle = Rc::clone(&next_render_event); + + layer_surface.quick_assign(move |layer_surface, event, _| { + match (event, nre_handle.get()) { + (zwlr_layer_surface_v1::Event::Closed, _) => { + nre_handle.set(Some(RenderEvent::Closed)); + } + (zwlr_layer_surface_v1::Event::Configure {serial, width, height}, next) + if next != Some(RenderEvent::Closed) => + { + layer_surface.ack_configure(serial); + nre_handle.set(Some(RenderEvent::Configure { width, height })); + } + (_, _) => {} + } + }); + + surface.commit(); + Surface { + surface, + layer_surface, + next_render_event, + pool, + dimensions: (0, 0) + } + } + + fn handle_events(&mut self) -> bool { + match self.next_render_event.take() { + Some(RenderEvent::Closed) => true, + Some(RenderEvent::Configure {width, height}) => { + if self.dimensions != (width, height) { + self.dimensions = (width, height); + self.draw(); + } + false + } + None => false, + } + } + + fn draw(&mut self) { + let stride = 4 * self.dimensions.0 as i32; + let width = self.dimensions.0 as i32; + let height = self.dimensions.1 as i32; + + let (canvas, buffer) = + self.pool.buffer(width, height, stride, wl_shm::Format::Argb8888) + .unwrap(); + for dst_pixel in canvas.chunks_exact_mut(4) { + let pixel = 0x01_00_8f_00u32.to_ne_bytes(); + dst_pixel[0] = pixel[0]; + dst_pixel[1] = pixel[1]; + dst_pixel[2] = pixel[2]; + dst_pixel[3] = pixel[3]; + } + + self.surface.attach(Some(&buffer), 0, 0); + self.surface.damage_buffer(0, 0, width, height); + self.surface.commit(); + } +} + +impl Drop for Surface { + fn drop(&mut self) { + self.layer_surface.destroy(); + self.surface.destroy(); + } +} + +fn main() -> anyhow::Result<()> { + + let (env, display, queue) = new_default_environment!( + MyEnv, + fields = [ + layer_shell: SimpleGlobal::new(), + ], + )?; + + let env_handle = env.clone(); + + let layer_shell = env.require_global::(); + + // List surfaces + let surfaces = Rc::new(RefCell::new(Vec::new())); + + let surfaces_handle = Rc::clone(&surfaces); + let output_handler = move |output: WlOutput, info: &OutputInfo| { + if info.obsolete { + surfaces_handle.borrow_mut().retain(|(i, _)| *i != info.id); + output.release(); + } else { + let surface = env_handle.create_surface().detach(); + let pool = env_handle.create_auto_pool().expect("Failed to create a memeory pool!"); + surfaces_handle.borrow_mut().push((info.id, Surface::new(&output, surface, &layer_shell.clone(), pool))); + } + }; + + // Process currently existing outputs + for output in env.get_all_outputs() { + if let Some(info) = with_output_info(&output, Clone::clone) { + output_handler(output, &info); + } + } + + let _listener_handle = env.listen_for_outputs(move |output, info, _| output_handler(output, info)); + let mut event_loop = calloop::EventLoop::<()>::try_new().expect("Failed to start event loop"); + + WaylandSource::new(queue).quick_insert(event_loop.handle()).unwrap(); + loop { + { + let mut surfaces = surfaces.borrow_mut(); + let mut i = 0; + while i != surfaces.len() { + if surfaces[i].1.handle_events() { + surfaces.remove(i); + } else { + i += 1; + } + } + } + + display.flush().unwrap(); + event_loop.dispatch(None, &mut ()).unwrap(); + } + //println!("Registry: {:#?}", env); +}