Add "hello world" clock application
This commit is contained in:
parent
6d7d032ee0
commit
2a5a0b7443
3 changed files with 1326 additions and 2 deletions
1047
Cargo.lock
generated
1047
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -4,3 +4,7 @@ version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
smithay-client-toolkit = "0.19"
|
||||||
|
wayland-client = "0.31"
|
||||||
|
cairo-rs = { version = "0.20", features = ["v1_16"] }
|
||||||
|
chrono = "0.4"
|
||||||
|
|
|
||||||
277
src/main.rs
277
src/main.rs
|
|
@ -1,3 +1,276 @@
|
||||||
fn main() {
|
use chrono::Local;
|
||||||
println!("Hello, world!");
|
use smithay_client_toolkit::{
|
||||||
|
compositor::{CompositorHandler, CompositorState},
|
||||||
|
delegate_compositor, delegate_layer, delegate_output, delegate_registry, delegate_shm,
|
||||||
|
output::{OutputHandler, OutputState},
|
||||||
|
registry::{ProvidesRegistryState, RegistryState},
|
||||||
|
registry_handlers,
|
||||||
|
shell::{
|
||||||
|
wlr_layer::{
|
||||||
|
Anchor, KeyboardInteractivity, Layer, LayerShell, LayerShellHandler, LayerSurface,
|
||||||
|
LayerSurfaceConfigure,
|
||||||
|
},
|
||||||
|
WaylandSurface,
|
||||||
|
},
|
||||||
|
shm::{slot::SlotPool, Shm, ShmHandler},
|
||||||
|
};
|
||||||
|
use wayland_client::{
|
||||||
|
globals::registry_queue_init,
|
||||||
|
protocol::{wl_output, wl_shm, wl_surface},
|
||||||
|
Connection, QueueHandle,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let conn = Connection::connect_to_env()?;
|
||||||
|
let (globals, mut event_queue) = registry_queue_init(&conn)?;
|
||||||
|
let qh = event_queue.handle();
|
||||||
|
|
||||||
|
let mut app = ClockApp {
|
||||||
|
registry_state: RegistryState::new(&globals),
|
||||||
|
output_state: OutputState::new(&globals, &qh),
|
||||||
|
compositor_state: CompositorState::bind(&globals, &qh)?,
|
||||||
|
shm_state: Shm::bind(&globals, &qh)?,
|
||||||
|
layer_shell: LayerShell::bind(&globals, &qh)?,
|
||||||
|
|
||||||
|
pool: None,
|
||||||
|
width: 400,
|
||||||
|
height: 200,
|
||||||
|
layer_surface: None,
|
||||||
|
configured: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create the layer surface
|
||||||
|
let surface = app.compositor_state.create_surface(&qh);
|
||||||
|
let layer_surface = app.layer_shell.create_layer_surface(
|
||||||
|
&qh,
|
||||||
|
surface,
|
||||||
|
Layer::Top,
|
||||||
|
Some("clock"),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
layer_surface.set_anchor(Anchor::TOP | Anchor::LEFT | Anchor::RIGHT);
|
||||||
|
layer_surface.set_size(app.width, app.height);
|
||||||
|
layer_surface.set_exclusive_zone(app.height as i32);
|
||||||
|
layer_surface.set_keyboard_interactivity(KeyboardInteractivity::None);
|
||||||
|
layer_surface.commit();
|
||||||
|
|
||||||
|
app.layer_surface = Some(layer_surface);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
event_queue.blocking_dispatch(&mut app)?;
|
||||||
|
|
||||||
|
if app.configured {
|
||||||
|
app.draw(&qh)?;
|
||||||
|
// Sleep briefly to reduce CPU usage
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ClockApp {
|
||||||
|
registry_state: RegistryState,
|
||||||
|
output_state: OutputState,
|
||||||
|
compositor_state: CompositorState,
|
||||||
|
shm_state: Shm,
|
||||||
|
layer_shell: LayerShell,
|
||||||
|
|
||||||
|
pool: Option<SlotPool>,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
layer_surface: Option<LayerSurface>,
|
||||||
|
configured: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClockApp {
|
||||||
|
fn draw(&mut self, _qh: &QueueHandle<Self>) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
if let Some(layer_surface) = &self.layer_surface {
|
||||||
|
let width = self.width;
|
||||||
|
let height = self.height;
|
||||||
|
let stride = width as i32 * 4;
|
||||||
|
|
||||||
|
let pool = self.pool.get_or_insert_with(|| {
|
||||||
|
SlotPool::new((width * height * 4) as usize, &self.shm_state).unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
let (buffer, canvas) = pool
|
||||||
|
.create_buffer(width as i32, height as i32, stride, wl_shm::Format::Argb8888)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Get current time
|
||||||
|
let now = Local::now();
|
||||||
|
let time_str = now.format("%H:%M:%S").to_string();
|
||||||
|
let date_str = now.format("%A, %B %d, %Y").to_string();
|
||||||
|
|
||||||
|
// Draw using cairo
|
||||||
|
// Safety: We ensure the buffer lifetime is valid for the cairo surface
|
||||||
|
unsafe {
|
||||||
|
let surface = cairo::ImageSurface::create_for_data_unsafe(
|
||||||
|
canvas.as_mut_ptr(),
|
||||||
|
cairo::Format::ARgb32,
|
||||||
|
width as i32,
|
||||||
|
height as i32,
|
||||||
|
stride,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let ctx = cairo::Context::new(&surface)?;
|
||||||
|
|
||||||
|
// Background
|
||||||
|
ctx.set_source_rgb(0.1, 0.1, 0.15);
|
||||||
|
ctx.paint()?;
|
||||||
|
|
||||||
|
// Draw time
|
||||||
|
ctx.set_source_rgb(1.0, 1.0, 1.0);
|
||||||
|
ctx.select_font_face("Sans", cairo::FontSlant::Normal, cairo::FontWeight::Bold);
|
||||||
|
ctx.set_font_size(60.0);
|
||||||
|
|
||||||
|
let time_extents = ctx.text_extents(&time_str)?;
|
||||||
|
let time_x = (width as f64 - time_extents.width()) / 2.0 - time_extents.x_bearing();
|
||||||
|
let time_y = height as f64 / 2.0 - 10.0;
|
||||||
|
ctx.move_to(time_x, time_y);
|
||||||
|
ctx.show_text(&time_str)?;
|
||||||
|
|
||||||
|
// Draw date
|
||||||
|
ctx.set_font_size(20.0);
|
||||||
|
ctx.select_font_face("Sans", cairo::FontSlant::Normal, cairo::FontWeight::Normal);
|
||||||
|
let date_extents = ctx.text_extents(&date_str)?;
|
||||||
|
let date_x = (width as f64 - date_extents.width()) / 2.0 - date_extents.x_bearing();
|
||||||
|
let date_y = height as f64 / 2.0 + 35.0;
|
||||||
|
ctx.move_to(date_x, date_y);
|
||||||
|
ctx.show_text(&date_str)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
layer_surface
|
||||||
|
.wl_surface()
|
||||||
|
.attach(Some(buffer.wl_buffer()), 0, 0);
|
||||||
|
layer_surface.wl_surface().damage_buffer(0, 0, width as i32, height as i32);
|
||||||
|
layer_surface.wl_surface().commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompositorHandler for ClockApp {
|
||||||
|
fn scale_factor_changed(
|
||||||
|
&mut self,
|
||||||
|
_conn: &Connection,
|
||||||
|
_qh: &QueueHandle<Self>,
|
||||||
|
_surface: &wl_surface::WlSurface,
|
||||||
|
_new_factor: i32,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transform_changed(
|
||||||
|
&mut self,
|
||||||
|
_conn: &Connection,
|
||||||
|
_qh: &QueueHandle<Self>,
|
||||||
|
_surface: &wl_surface::WlSurface,
|
||||||
|
_new_transform: wl_output::Transform,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(
|
||||||
|
&mut self,
|
||||||
|
_conn: &Connection,
|
||||||
|
qh: &QueueHandle<Self>,
|
||||||
|
_surface: &wl_surface::WlSurface,
|
||||||
|
_time: u32,
|
||||||
|
) {
|
||||||
|
let _ = self.draw(qh);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn surface_enter(
|
||||||
|
&mut self,
|
||||||
|
_conn: &Connection,
|
||||||
|
_qh: &QueueHandle<Self>,
|
||||||
|
_surface: &wl_surface::WlSurface,
|
||||||
|
_output: &wl_output::WlOutput,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn surface_leave(
|
||||||
|
&mut self,
|
||||||
|
_conn: &Connection,
|
||||||
|
_qh: &QueueHandle<Self>,
|
||||||
|
_surface: &wl_surface::WlSurface,
|
||||||
|
_output: &wl_output::WlOutput,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OutputHandler for ClockApp {
|
||||||
|
fn output_state(&mut self) -> &mut OutputState {
|
||||||
|
&mut self.output_state
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_output(
|
||||||
|
&mut self,
|
||||||
|
_conn: &Connection,
|
||||||
|
_qh: &QueueHandle<Self>,
|
||||||
|
_output: wl_output::WlOutput,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_output(
|
||||||
|
&mut self,
|
||||||
|
_conn: &Connection,
|
||||||
|
_qh: &QueueHandle<Self>,
|
||||||
|
_output: wl_output::WlOutput,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output_destroyed(
|
||||||
|
&mut self,
|
||||||
|
_conn: &Connection,
|
||||||
|
_qh: &QueueHandle<Self>,
|
||||||
|
_output: wl_output::WlOutput,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LayerShellHandler for ClockApp {
|
||||||
|
fn closed(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>, _layer: &LayerSurface) {
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configure(
|
||||||
|
&mut self,
|
||||||
|
_conn: &Connection,
|
||||||
|
qh: &QueueHandle<Self>,
|
||||||
|
_layer: &LayerSurface,
|
||||||
|
configure: LayerSurfaceConfigure,
|
||||||
|
_serial: u32,
|
||||||
|
) {
|
||||||
|
if configure.new_size.0 != 0 {
|
||||||
|
self.width = configure.new_size.0;
|
||||||
|
}
|
||||||
|
if configure.new_size.1 != 0 {
|
||||||
|
self.height = configure.new_size.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.configured = true;
|
||||||
|
let _ = self.draw(qh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShmHandler for ClockApp {
|
||||||
|
fn shm_state(&mut self) -> &mut Shm {
|
||||||
|
&mut self.shm_state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate_compositor!(ClockApp);
|
||||||
|
delegate_output!(ClockApp);
|
||||||
|
delegate_shm!(ClockApp);
|
||||||
|
delegate_layer!(ClockApp);
|
||||||
|
|
||||||
|
delegate_registry!(ClockApp);
|
||||||
|
|
||||||
|
impl ProvidesRegistryState for ClockApp {
|
||||||
|
fn registry(&mut self) -> &mut RegistryState {
|
||||||
|
&mut self.registry_state
|
||||||
|
}
|
||||||
|
|
||||||
|
registry_handlers![OutputState];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue