mirror of
https://codeberg.org/waydeer/layer-shika.git
synced 2026-01-22 11:35:54 +00:00
192 lines
6.2 KiB
Rust
192 lines
6.2 KiB
Rust
use crate::errors::Result;
|
|
use crate::rendering::femtovg::renderable_window::RenderableWindow;
|
|
use crate::wayland::managed_proxies::{
|
|
ManagedWlSurface, ManagedZwlrLayerSurfaceV1, ManagedWpFractionalScaleV1, ManagedWpViewport,
|
|
};
|
|
use crate::wayland::surfaces::dimensions::SurfaceDimensionsExt;
|
|
use layer_shika_domain::surface_dimensions::SurfaceDimensions;
|
|
use log::{error, info};
|
|
use slint::PhysicalSize;
|
|
use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
|
|
use std::rc::Rc;
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
enum ScalingMode {
|
|
FractionalWithViewport,
|
|
FractionalOnly,
|
|
Integer,
|
|
}
|
|
|
|
pub struct SurfaceRendererParams<W: RenderableWindow> {
|
|
pub window: Rc<W>,
|
|
pub surface: ManagedWlSurface,
|
|
pub layer_surface: ManagedZwlrLayerSurfaceV1,
|
|
pub viewport: Option<ManagedWpViewport>,
|
|
pub fractional_scale: Option<ManagedWpFractionalScaleV1>,
|
|
pub height: u32,
|
|
pub size: PhysicalSize,
|
|
}
|
|
|
|
pub struct SurfaceRenderer<W: RenderableWindow> {
|
|
window: Rc<W>,
|
|
surface: ManagedWlSurface,
|
|
layer_surface: ManagedZwlrLayerSurfaceV1,
|
|
viewport: Option<ManagedWpViewport>,
|
|
fractional_scale: Option<ManagedWpFractionalScaleV1>,
|
|
height: u32,
|
|
size: PhysicalSize,
|
|
logical_size: PhysicalSize,
|
|
}
|
|
|
|
impl<W: RenderableWindow> SurfaceRenderer<W> {
|
|
#[must_use]
|
|
pub fn new(params: SurfaceRendererParams<W>) -> Self {
|
|
Self {
|
|
window: params.window,
|
|
surface: params.surface,
|
|
layer_surface: params.layer_surface,
|
|
viewport: params.viewport,
|
|
fractional_scale: params.fractional_scale,
|
|
height: params.height,
|
|
size: params.size,
|
|
logical_size: PhysicalSize::default(),
|
|
}
|
|
}
|
|
|
|
pub fn render_frame_if_dirty(&self) -> Result<()> {
|
|
self.window.render_frame_if_dirty()
|
|
}
|
|
|
|
pub const fn window(&self) -> &Rc<W> {
|
|
&self.window
|
|
}
|
|
|
|
pub fn layer_surface(&self) -> Rc<ZwlrLayerSurfaceV1> {
|
|
Rc::clone(self.layer_surface.inner())
|
|
}
|
|
|
|
pub const fn height(&self) -> u32 {
|
|
self.height
|
|
}
|
|
|
|
pub const fn size(&self) -> PhysicalSize {
|
|
self.size
|
|
}
|
|
|
|
const fn determine_scaling_mode(&self) -> ScalingMode {
|
|
if self.fractional_scale.is_some() && self.viewport.is_some() {
|
|
ScalingMode::FractionalWithViewport
|
|
} else if self.fractional_scale.is_some() {
|
|
ScalingMode::FractionalOnly
|
|
} else {
|
|
ScalingMode::Integer
|
|
}
|
|
}
|
|
|
|
#[allow(clippy::cast_precision_loss)]
|
|
fn configure_slint_window(
|
|
&self,
|
|
dimensions: &SurfaceDimensions,
|
|
mode: ScalingMode,
|
|
scale_factor: f32,
|
|
) {
|
|
match mode {
|
|
ScalingMode::FractionalWithViewport => {
|
|
self.window.set_scale_factor(scale_factor);
|
|
self.window
|
|
.set_size(slint::WindowSize::Logical(slint::LogicalSize::new(
|
|
dimensions.logical_width() as f32,
|
|
dimensions.logical_height() as f32,
|
|
)));
|
|
}
|
|
ScalingMode::FractionalOnly => {
|
|
self.window
|
|
.set_scale_factor(dimensions.buffer_scale() as f32);
|
|
self.window
|
|
.set_size(slint::WindowSize::Logical(slint::LogicalSize::new(
|
|
dimensions.logical_width() as f32,
|
|
dimensions.logical_height() as f32,
|
|
)));
|
|
}
|
|
ScalingMode::Integer => {
|
|
self.window.set_scale_factor(scale_factor);
|
|
self.window.set_size(slint::WindowSize::Physical(
|
|
dimensions.to_slint_physical_size(),
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(clippy::cast_possible_wrap)]
|
|
fn configure_wayland_surface(&self, dimensions: &SurfaceDimensions, mode: ScalingMode) {
|
|
match mode {
|
|
ScalingMode::FractionalWithViewport => {
|
|
self.surface.set_buffer_scale(1);
|
|
if let Some(viewport) = &self.viewport {
|
|
viewport.set_destination(
|
|
dimensions.logical_width() as i32,
|
|
dimensions.logical_height() as i32,
|
|
);
|
|
}
|
|
}
|
|
ScalingMode::FractionalOnly | ScalingMode::Integer => {
|
|
self.surface.set_buffer_scale(dimensions.buffer_scale());
|
|
}
|
|
}
|
|
|
|
self.surface.commit();
|
|
}
|
|
|
|
pub fn update_size(&mut self, width: u32, height: u32, scale_factor: f32) {
|
|
if width == 0 || height == 0 {
|
|
info!("Skipping update_size with zero dimension: {width}x{height}");
|
|
return;
|
|
}
|
|
|
|
let dimensions = match SurfaceDimensions::calculate(width, height, scale_factor) {
|
|
Ok(d) => d,
|
|
Err(e) => {
|
|
error!("Failed to calculate surface dimensions: {e}");
|
|
return;
|
|
}
|
|
};
|
|
|
|
self.apply_surface_dimensions(dimensions, scale_factor);
|
|
}
|
|
|
|
pub fn apply_surface_dimensions(&mut self, dimensions: SurfaceDimensions, scale_factor: f32) {
|
|
let scaling_mode = self.determine_scaling_mode();
|
|
|
|
info!(
|
|
"Updating window size: logical {}x{}, physical {}x{}, scale {}, buffer_scale {}, mode {:?}",
|
|
dimensions.logical_width(),
|
|
dimensions.logical_height(),
|
|
dimensions.physical_width(),
|
|
dimensions.physical_height(),
|
|
scale_factor,
|
|
dimensions.buffer_scale(),
|
|
scaling_mode
|
|
);
|
|
|
|
self.configure_slint_window(&dimensions, scaling_mode, scale_factor);
|
|
self.configure_wayland_surface(&dimensions, scaling_mode);
|
|
|
|
info!("Window physical size: {:?}", self.window.size());
|
|
|
|
self.size = dimensions.to_slint_physical_size();
|
|
self.logical_size = dimensions.to_slint_logical_size();
|
|
RenderableWindow::request_redraw(self.window.as_ref());
|
|
}
|
|
|
|
pub const fn logical_size(&self) -> PhysicalSize {
|
|
self.logical_size
|
|
}
|
|
|
|
pub const fn fractional_scale(&self) -> Option<&ManagedWpFractionalScaleV1> {
|
|
self.fractional_scale.as_ref()
|
|
}
|
|
|
|
pub fn commit_surface(&self) {
|
|
self.surface.commit();
|
|
}
|
|
}
|