From c6d9d21caf846db50f8eef82d450b97fd8c5e320 Mon Sep 17 00:00:00 2001 From: MaxVerevkin Date: Sat, 4 Feb 2023 22:15:55 +0200 Subject: implement fractional scaling support --- Cargo.toml | 5 ++++- src/bar.rs | 47 +++++++++++++++++++++++++++++++---------------- src/protocol.rs | 2 ++ src/state.rs | 41 +++++++++++++++++++++++++++++++++-------- 4 files changed, 70 insertions(+), 25 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 729f9eb..d7455f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,11 +16,14 @@ memchr = "2" thiserror = "1.0.38" wayrs-client = { version = "0.3", features = ["tokio"] } -wayrs-protocols = { version = "0.3", features = ["wlr-layer-shell-unstable-v1"] } wayrs-shm-alloc = "0.3" xcursor = "0.3.4" +[dependencies.wayrs-protocols] +version = "0.3" +features = ["wlr-layer-shell-unstable-v1", "viewporter", "fractional-scale-v1"] + [dependencies.tokio] version = "1" features = ["macros", "net", "rt", "sync", "io-util", "process"] diff --git a/src/bar.rs b/src/bar.rs index 2d29dca..3f3e958 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -23,9 +23,12 @@ pub struct Bar { pub frame_cb: Option, pub width: u32, pub height: u32, - pub scale: i32, + pub scale: u32, + pub scale120: Option, pub surface: WlSurface, pub layer_surface: ZwlrLayerSurfaceV1, + pub viewport: WpViewport, + pub fractional_scale: Option, pub blocks_btns: ButtonManager<(Option, Option)>, pub wm_info: WmInfo, pub tags_btns: ButtonManager, @@ -84,17 +87,28 @@ impl Bar { pub fn frame(&mut self, conn: &mut Connection, ss: &mut SharedState) { assert!(self.configured); - let stride = 4 * self.width as i32; - let width = self.width as i32; - let height = self.height as i32; - let width_f = width as f64; - let height_f = height as f64; + let (pix_width, pix_height, scale_f) = match self.scale120 { + Some(scale120) => ( + // rounding halfway away from zero + (self.width * scale120 + 60) / 120, + (self.height * scale120 + 60) / 120, + scale120 as f64 / 120.0, + ), + None => ( + self.width * self.scale, + self.height * self.scale, + self.scale as f64, + ), + }; + + let width_f = self.width as f64; + let height_f = self.height as f64; let (buffer, canvas) = ss.shm.alloc_buffer( conn, - width * self.scale, - height * self.scale, - stride * self.scale, + pix_width as i32, + pix_height as i32, + pix_width as i32 * 4, wl_shm::Format::Argb8888, ); @@ -102,16 +116,15 @@ impl Bar { cairo::ImageSurface::create_for_data_unsafe( canvas.as_mut_ptr(), cairo::Format::ARgb32, - width * self.scale, - height * self.scale, - stride * self.scale, + pix_width as i32, + pix_height as i32, + pix_width as i32 * 4, ) .expect("cairo surface") }; let cairo_ctx = cairo::Context::new(&cairo_surf).expect("cairo context"); - cairo_ctx.scale(self.scale as f64, self.scale as f64); - self.surface.set_buffer_scale(conn, self.scale); + cairo_ctx.scale(scale_f, scale_f); // Background cairo_ctx.save().unwrap(); @@ -217,9 +230,11 @@ impl Bar { height_f, ); + self.viewport + .set_destination(conn, self.width as i32, self.height as i32); + self.surface.attach(conn, buffer.wl, 0, 0); - self.surface - .damage_buffer(conn, 0, 0, width * self.scale, height * self.scale); + self.surface.damage(conn, 0, 0, i32::MAX, i32::MAX); self.surface.commit(conn); } diff --git a/src/protocol.rs b/src/protocol.rs index 6546743..e8f464e 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -2,6 +2,8 @@ use wayrs_client; pub use wayrs_client::protocol::*; +pub use wayrs_protocols::fractional_scale_v1::*; +pub use wayrs_protocols::viewporter::*; pub use wayrs_protocols::wlr_layer_shell_unstable_v1::*; wayrs_client::scanner::generate!("protocols/river-status-unstable-v1.xml"); wayrs_client::scanner::generate!("protocols/river-control-unstable-v1.xml"); diff --git a/src/state.rs b/src/state.rs index b4123d3..5a18a80 100644 --- a/src/state.rs +++ b/src/state.rs @@ -18,6 +18,8 @@ use crate::{ pub struct State { wl_compositor: WlCompositor, layer_shell: ZwlrLayerShellV1, + viewporter: WpViewporter, + fractional_scale_manager: Option, pub seats: Vec, pub bars: Vec, @@ -64,12 +66,10 @@ impl State { .is_ok(); let mut this = Self { - wl_compositor: globals - .bind(conn, 4..=5) - .expect("could not bind wl_compositor"), - layer_shell: globals - .bind(conn, 1..=4) - .expect("could not bind layer_shell"), + wl_compositor: globals.bind(conn, 4..=5).unwrap(), + layer_shell: globals.bind(conn, 1..=4).unwrap(), + viewporter: globals.bind(conn, 1..=1).unwrap(), + fractional_scale_manager: globals.bind(conn, 1..=1).ok(), seats: Vec::new(), bars: Vec::new(), @@ -156,6 +156,10 @@ impl State { let surface = self.wl_compositor.create_surface(conn); + let fractional_scale = self + .fractional_scale_manager + .map(|mgr| mgr.get_fractional_scale_with_cb(conn, surface, fractional_scale_cb)); + let layer_surface = self.layer_shell.get_layer_surface_with_cb( conn, surface, @@ -196,7 +200,10 @@ impl State { width: 0, height: self.shared_state.config.height, scale: 1, + scale120: None, surface, + viewport: self.viewporter.get_viewport(conn, surface), + fractional_scale, layer_surface, blocks_btns: Default::default(), wm_info: Default::default(), @@ -299,7 +306,7 @@ fn wl_output_cb( .iter_mut() .find(|bar| bar.output == output) .unwrap(); - bar.scale = scale; + bar.scale = scale as u32; // If bar is not configured yet, it is because we were waiting for the "scale" event // before commiting the surface. Otherwise, there is no need to do any redrawing (we'll // do that after "configure" event). @@ -449,7 +456,7 @@ fn wl_pointer_cb( .set_cursor( conn, "default", - bar.scale as u32, + bar.scale, args.serial, &mut state.shared_state.shm, seat.cursor_surface, @@ -485,6 +492,24 @@ fn wl_pointer_cb( } } +fn fractional_scale_cb( + conn: &mut Connection, + state: &mut State, + fractional_scale: WpFractionalScaleV1, + event: wp_fractional_scale_v1::Event, +) { + let wp_fractional_scale_v1::Event::PreferredScale(scale120) = event; + let bar = state + .bars + .iter_mut() + .find(|b| b.fractional_scale == Some(fractional_scale)) + .unwrap(); + if bar.scale120 != Some(scale120) { + bar.scale120 = Some(scale120); + bar.request_frame(conn); + } +} + fn wm_info_cb(conn: &mut Connection, state: &mut State, output: WlOutput, info: WmInfo) { let bar = state.bars.iter_mut().find(|b| b.output == output).unwrap(); bar.set_wm_info(info); -- cgit v1.3.1