mirror of
https://codeberg.org/waydeer/layer-shika.git
synced 2026-01-22 07:05:56 +00:00
287 lines
9.9 KiB
Rust
287 lines
9.9 KiB
Rust
use super::callbacks::{LockCallbackContext, LockCallbackExt};
|
|
use crate::errors::Result;
|
|
use crate::rendering::femtovg::main_window::FemtoVGWindow;
|
|
use crate::rendering::femtovg::renderable_window::RenderableWindow;
|
|
use crate::rendering::slint_integration::platform::CustomSlintPlatform;
|
|
use crate::wayland::session_lock::lock_surface::LockSurface;
|
|
use crate::wayland::surfaces::component_state::ComponentState;
|
|
use crate::wayland::surfaces::display_metrics::DisplayMetrics;
|
|
use layer_shika_domain::surface_dimensions::SurfaceDimensions;
|
|
use layer_shika_domain::value_objects::output_handle::OutputHandle;
|
|
use layer_shika_domain::value_objects::output_info::OutputInfo;
|
|
use log::info;
|
|
use slint::{
|
|
LogicalPosition, LogicalSize, WindowSize,
|
|
platform::{WindowAdapter, WindowEvent},
|
|
};
|
|
use slint_interpreter::{CompilationResult, ComponentDefinition};
|
|
use std::rc::Rc;
|
|
|
|
use super::callbacks::LockCallback;
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
pub enum LockScalingMode {
|
|
FractionalWithViewport,
|
|
FractionalOnly,
|
|
Integer,
|
|
}
|
|
|
|
pub struct LockSurfaceOutputContext {
|
|
pub output_handle: OutputHandle,
|
|
pub output_info: Option<OutputInfo>,
|
|
pub primary_handle: Option<OutputHandle>,
|
|
pub active_handle: Option<OutputHandle>,
|
|
}
|
|
|
|
pub struct LockConfigureContext {
|
|
pub scale_factor: f32,
|
|
pub component_definition: ComponentDefinition,
|
|
pub compilation_result: Option<Rc<CompilationResult>>,
|
|
pub platform: Rc<CustomSlintPlatform>,
|
|
pub callbacks: Vec<LockCallback>,
|
|
pub component_name: String,
|
|
pub output_handle: OutputHandle,
|
|
pub output_info: Option<OutputInfo>,
|
|
pub primary_handle: Option<OutputHandle>,
|
|
pub active_handle: Option<OutputHandle>,
|
|
}
|
|
|
|
pub struct ActiveLockSurface {
|
|
surface: LockSurface,
|
|
window: Rc<FemtoVGWindow>,
|
|
component: Option<ComponentState>,
|
|
scale_factor: f32,
|
|
has_fractional_scale: bool,
|
|
output_handle: Option<OutputHandle>,
|
|
component_name: Option<String>,
|
|
output_info: Option<OutputInfo>,
|
|
primary_handle: Option<OutputHandle>,
|
|
active_handle: Option<OutputHandle>,
|
|
}
|
|
|
|
impl ActiveLockSurface {
|
|
pub fn new(surface: LockSurface, window: Rc<FemtoVGWindow>) -> Self {
|
|
Self {
|
|
has_fractional_scale: surface.fractional_scale().is_some(),
|
|
surface,
|
|
window,
|
|
component: None,
|
|
scale_factor: 1.0,
|
|
output_handle: None,
|
|
component_name: None,
|
|
output_info: None,
|
|
primary_handle: None,
|
|
active_handle: None,
|
|
}
|
|
}
|
|
|
|
pub fn handle_configure(
|
|
&mut self,
|
|
serial: u32,
|
|
width: u32,
|
|
height: u32,
|
|
context: &LockConfigureContext,
|
|
) -> Result<()> {
|
|
self.surface.handle_configure(serial, width, height);
|
|
self.scale_factor = context.scale_factor;
|
|
self.output_handle = Some(context.output_handle);
|
|
self.component_name = Some(context.component_name.clone());
|
|
self.output_info.clone_from(&context.output_info);
|
|
self.primary_handle = context.primary_handle;
|
|
self.active_handle = context.active_handle;
|
|
let dimensions = match SurfaceDimensions::calculate(width, height, context.scale_factor) {
|
|
Ok(dimensions) => dimensions,
|
|
Err(err) => {
|
|
info!("Failed to calculate lock surface dimensions: {err}");
|
|
return Ok(());
|
|
}
|
|
};
|
|
let scaling_mode = self.scaling_mode();
|
|
info!(
|
|
"Lock surface dimensions: logical {}x{}, physical {}x{}, scale {}, mode {:?}",
|
|
dimensions.logical_width(),
|
|
dimensions.logical_height(),
|
|
dimensions.physical_width(),
|
|
dimensions.physical_height(),
|
|
context.scale_factor,
|
|
scaling_mode
|
|
);
|
|
self.configure_window(&dimensions, scaling_mode, context.scale_factor);
|
|
self.configure_surface(&dimensions, scaling_mode);
|
|
|
|
if self.component.is_none() {
|
|
context.platform.add_window(Rc::clone(&self.window));
|
|
let component = ComponentState::new(
|
|
context.component_definition.clone(),
|
|
context.compilation_result.clone(),
|
|
&self.window,
|
|
)?;
|
|
self.window
|
|
.window()
|
|
.dispatch_event(WindowEvent::WindowActiveChanged(true));
|
|
|
|
let callback_context = LockCallbackContext::new(
|
|
context.component_name.clone(),
|
|
context.output_handle,
|
|
context.output_info.clone(),
|
|
context.primary_handle,
|
|
context.active_handle,
|
|
);
|
|
|
|
for callback in &context.callbacks {
|
|
if let Err(err) =
|
|
callback.apply_with_context(component.component_instance(), &callback_context)
|
|
{
|
|
info!(
|
|
"Failed to register lock callback '{}': {err}",
|
|
callback.name()
|
|
);
|
|
} else if callback.should_apply(&callback_context) {
|
|
info!("Registered lock callback '{}'", callback.name());
|
|
} else {
|
|
info!(
|
|
"Skipping callback '{}' due to selector filter (output {:?})",
|
|
callback.name(),
|
|
context.output_handle
|
|
);
|
|
}
|
|
}
|
|
self.component = Some(component);
|
|
}
|
|
|
|
RenderableWindow::request_redraw(self.window.as_ref());
|
|
Ok(())
|
|
}
|
|
|
|
pub fn render_frame_if_dirty(&self) -> Result<()> {
|
|
self.window.render_frame_if_dirty()
|
|
}
|
|
|
|
pub fn handle_fractional_scale(&mut self, scale_120ths: u32) {
|
|
let scale_factor = DisplayMetrics::scale_factor_from_120ths(scale_120ths);
|
|
self.scale_factor = scale_factor;
|
|
if self.surface.width() == 0 || self.surface.height() == 0 {
|
|
return;
|
|
}
|
|
let Ok(dimensions) =
|
|
SurfaceDimensions::calculate(self.surface.width(), self.surface.height(), scale_factor)
|
|
else {
|
|
return;
|
|
};
|
|
let scaling_mode = self.scaling_mode();
|
|
self.configure_window(&dimensions, scaling_mode, scale_factor);
|
|
self.configure_surface(&dimensions, scaling_mode);
|
|
RenderableWindow::request_redraw(self.window.as_ref());
|
|
}
|
|
|
|
pub fn apply_callback(&self, callback: &LockCallback) {
|
|
let Some(component) = self.component.as_ref() else {
|
|
return;
|
|
};
|
|
|
|
let Some(component_name) = &self.component_name else {
|
|
return;
|
|
};
|
|
|
|
let Some(output_handle) = self.output_handle else {
|
|
return;
|
|
};
|
|
|
|
let callback_context = LockCallbackContext::new(
|
|
component_name.clone(),
|
|
output_handle,
|
|
self.output_info.clone(),
|
|
self.primary_handle,
|
|
self.active_handle,
|
|
);
|
|
|
|
if let Err(err) =
|
|
callback.apply_with_context(component.component_instance(), &callback_context)
|
|
{
|
|
info!(
|
|
"Failed to register lock callback '{}': {err}",
|
|
callback.name()
|
|
);
|
|
}
|
|
}
|
|
|
|
fn scaling_mode(&self) -> LockScalingMode {
|
|
if self.surface.has_fractional_scale() && self.surface.has_viewport() {
|
|
LockScalingMode::FractionalWithViewport
|
|
} else if self.surface.has_fractional_scale() {
|
|
LockScalingMode::FractionalOnly
|
|
} else {
|
|
LockScalingMode::Integer
|
|
}
|
|
}
|
|
|
|
#[allow(clippy::cast_precision_loss)]
|
|
fn configure_window(
|
|
&self,
|
|
dimensions: &SurfaceDimensions,
|
|
mode: LockScalingMode,
|
|
scale_factor: f32,
|
|
) {
|
|
match mode {
|
|
LockScalingMode::FractionalWithViewport | LockScalingMode::FractionalOnly => {
|
|
RenderableWindow::set_scale_factor(self.window.as_ref(), scale_factor);
|
|
self.window.set_size(WindowSize::Logical(LogicalSize::new(
|
|
dimensions.logical_width() as f32,
|
|
dimensions.logical_height() as f32,
|
|
)));
|
|
}
|
|
LockScalingMode::Integer => {
|
|
RenderableWindow::set_scale_factor(self.window.as_ref(), scale_factor);
|
|
self.window
|
|
.set_size(WindowSize::Physical(slint::PhysicalSize::new(
|
|
dimensions.physical_width(),
|
|
dimensions.physical_height(),
|
|
)));
|
|
}
|
|
}
|
|
}
|
|
|
|
fn configure_surface(&self, dimensions: &SurfaceDimensions, mode: LockScalingMode) {
|
|
match mode {
|
|
LockScalingMode::FractionalWithViewport => {
|
|
self.surface.configure_fractional_viewport(
|
|
dimensions.logical_width(),
|
|
dimensions.logical_height(),
|
|
);
|
|
}
|
|
LockScalingMode::FractionalOnly | LockScalingMode::Integer => {
|
|
self.surface
|
|
.configure_buffer_scale(dimensions.buffer_scale());
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(clippy::cast_possible_truncation)]
|
|
pub fn to_logical_position(&self, surface_x: f64, surface_y: f64) -> LogicalPosition {
|
|
if self.has_fractional_scale {
|
|
let x = surface_x as f32;
|
|
let y = surface_y as f32;
|
|
LogicalPosition::new(x, y)
|
|
} else {
|
|
let x = (surface_x / f64::from(self.scale_factor)) as f32;
|
|
let y = (surface_y / f64::from(self.scale_factor)) as f32;
|
|
LogicalPosition::new(x, y)
|
|
}
|
|
}
|
|
|
|
pub fn dispatch_event(&self, event: WindowEvent) {
|
|
self.window.window().dispatch_event(event);
|
|
}
|
|
|
|
pub fn window_rc(&self) -> Rc<FemtoVGWindow> {
|
|
Rc::clone(&self.window)
|
|
}
|
|
|
|
pub const fn surface(&self) -> &LockSurface {
|
|
&self.surface
|
|
}
|
|
|
|
pub const fn component(&self) -> Option<&ComponentState> {
|
|
self.component.as_ref()
|
|
}
|
|
}
|