refactor: minor lock callback refactor

This commit is contained in:
drendog 2026-01-18 00:41:03 +01:00
parent 6cbbce773f
commit d5b4953c1a
Signed by: dwenya
GPG key ID: 8DD77074645332D0
3 changed files with 215 additions and 77 deletions

View file

@ -4,7 +4,99 @@ use layer_shika_domain::value_objects::output_info::OutputInfo;
use slint_interpreter::{ComponentInstance, Value}; use slint_interpreter::{ComponentInstance, Value};
use std::rc::Rc; use std::rc::Rc;
pub type LockCallbackHandler = Rc<dyn Fn(&[Value]) -> Value>; pub(crate) trait FilterContext {
fn matches_filter(&self, filter: &dyn Fn(&Self) -> bool) -> bool {
filter(self)
}
}
type FilterFn<Ctx> = Box<dyn Fn(&Ctx) -> bool>;
pub(crate) struct CallbackEntry<Ctx: FilterContext, Handler> {
name: String,
handler: Handler,
filter: Option<FilterFn<Ctx>>,
}
impl<Ctx: FilterContext, Handler: Clone> CallbackEntry<Ctx, Handler> {
fn new(name: impl Into<String>, handler: Handler) -> Self {
Self {
name: name.into(),
handler,
filter: None,
}
}
fn with_filter<F>(name: impl Into<String>, handler: Handler, filter: F) -> Self
where
F: Fn(&Ctx) -> bool + 'static,
{
Self {
name: name.into(),
handler,
filter: Some(Box::new(filter)),
}
}
pub fn should_apply(&self, context: &Ctx) -> bool {
self.filter
.as_ref()
.is_none_or(|f| context.matches_filter(f.as_ref()))
}
pub fn name(&self) -> &str {
&self.name
}
pub fn handler(&self) -> &Handler {
&self.handler
}
}
impl<Ctx: FilterContext, Handler: Clone> Clone for CallbackEntry<Ctx, Handler> {
fn clone(&self) -> Self {
Self {
name: self.name.clone(),
handler: self.handler.clone(),
filter: None,
}
}
}
pub type CallbackHandler = Rc<dyn Fn(&[Value]) -> Value>;
pub struct LockCallbackContext {
pub component_name: String,
pub output_handle: OutputHandle,
pub output_info: Option<OutputInfo>,
pub primary_handle: Option<OutputHandle>,
pub active_handle: Option<OutputHandle>,
}
impl LockCallbackContext {
pub fn new(
component_name: String,
output_handle: OutputHandle,
output_info: Option<OutputInfo>,
primary_handle: Option<OutputHandle>,
active_handle: Option<OutputHandle>,
) -> Self {
Self {
component_name,
output_handle,
output_info,
primary_handle,
active_handle,
}
}
}
impl FilterContext for LockCallbackContext {}
pub type LockCallbackEntry = CallbackEntry<LockCallbackContext, CallbackHandler>;
pub type LockCallback = LockCallbackEntry;
pub type OutputFilter = Rc< pub type OutputFilter = Rc<
dyn Fn( dyn Fn(
&str, &str,
@ -15,66 +107,64 @@ pub type OutputFilter = Rc<
) -> bool, ) -> bool,
>; >;
#[derive(Clone)] pub fn create_lock_callback(name: impl Into<String>, handler: CallbackHandler) -> LockCallback {
pub struct LockCallback { LockCallbackEntry::new(name, handler)
name: String,
handler: LockCallbackHandler,
filter: Option<OutputFilter>,
} }
impl LockCallback { pub fn create_lock_callback_with_output_filter<F>(
pub fn new(name: impl Into<String>, handler: LockCallbackHandler) -> Self {
Self {
name: name.into(),
handler,
filter: None,
}
}
pub fn with_filter(
name: impl Into<String>, name: impl Into<String>,
handler: LockCallbackHandler, handler: CallbackHandler,
filter: OutputFilter, output_filter: F,
) -> Self { ) -> LockCallback
Self { where
name: name.into(), F: Fn(
handler, &str,
filter: Some(filter), OutputHandle,
} Option<&OutputInfo>,
} Option<OutputHandle>,
Option<OutputHandle>,
) -> bool
+ 'static,
{
LockCallbackEntry::with_filter(name, handler, move |ctx: &LockCallbackContext| {
output_filter(
&ctx.component_name,
ctx.output_handle,
ctx.output_info.as_ref(),
ctx.primary_handle,
ctx.active_handle,
)
})
}
pub fn should_apply( pub trait LockCallbackExt {
fn apply_to_component(&self, component: &ComponentInstance) -> Result<()>;
fn apply_with_context(
&self, &self,
component_name: &str, component: &ComponentInstance,
output_handle: OutputHandle, context: &LockCallbackContext,
output_info: Option<&OutputInfo>, ) -> Result<()>;
primary_handle: Option<OutputHandle>, }
active_handle: Option<OutputHandle>,
) -> bool {
self.filter.as_ref().map_or_else(
|| true,
|f| {
f(
component_name,
output_handle,
output_info,
primary_handle,
active_handle,
)
},
)
}
pub fn apply_to(&self, component: &ComponentInstance) -> Result<()> { impl LockCallbackExt for LockCallbackEntry {
let handler = Rc::clone(&self.handler); fn apply_to_component(&self, component: &ComponentInstance) -> Result<()> {
let handler = Rc::clone(self.handler());
component component
.set_callback(&self.name, move |args| handler(args)) .set_callback(self.name(), move |args| handler(args))
.map_err(|e| LayerShikaError::InvalidInput { .map_err(|e| LayerShikaError::InvalidInput {
message: format!("Failed to register callback '{}': {e}", self.name), message: format!("Failed to register callback '{}': {e}", self.name()),
}) })
} }
pub const fn name(&self) -> &String { fn apply_with_context(
&self.name &self,
component: &ComponentInstance,
context: &LockCallbackContext,
) -> Result<()> {
if !self.should_apply(context) {
return Ok(());
}
self.apply_to_component(component)
} }
} }

View file

@ -1,3 +1,4 @@
use super::callbacks::{LockCallbackContext, LockCallbackExt};
use crate::errors::Result; use crate::errors::Result;
use crate::rendering::femtovg::main_window::FemtoVGWindow; use crate::rendering::femtovg::main_window::FemtoVGWindow;
use crate::rendering::femtovg::renderable_window::RenderableWindow; use crate::rendering::femtovg::renderable_window::RenderableWindow;
@ -51,6 +52,11 @@ pub struct ActiveLockSurface {
component: Option<ComponentState>, component: Option<ComponentState>,
scale_factor: f32, scale_factor: f32,
has_fractional_scale: bool, 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 { impl ActiveLockSurface {
@ -61,6 +67,11 @@ impl ActiveLockSurface {
window, window,
component: None, component: None,
scale_factor: 1.0, scale_factor: 1.0,
output_handle: None,
component_name: None,
output_info: None,
primary_handle: None,
active_handle: None,
} }
} }
@ -73,6 +84,11 @@ impl ActiveLockSurface {
) -> Result<()> { ) -> Result<()> {
self.surface.handle_configure(serial, width, height); self.surface.handle_configure(serial, width, height);
self.scale_factor = context.scale_factor; 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) { let dimensions = match SurfaceDimensions::calculate(width, height, context.scale_factor) {
Ok(dimensions) => dimensions, Ok(dimensions) => dimensions,
Err(err) => { Err(err) => {
@ -103,22 +119,25 @@ impl ActiveLockSurface {
self.window self.window
.window() .window()
.dispatch_event(WindowEvent::WindowActiveChanged(true)); .dispatch_event(WindowEvent::WindowActiveChanged(true));
for callback in &context.callbacks {
if callback.should_apply( let callback_context = LockCallbackContext::new(
&context.component_name, context.component_name.clone(),
context.output_handle, context.output_handle,
context.output_info.as_ref(), context.output_info.clone(),
context.primary_handle, context.primary_handle,
context.active_handle, context.active_handle,
) { );
if let Err(err) = callback.apply_to(component.component_instance()) {
for callback in &context.callbacks {
if let Err(err) =
callback.apply_with_context(component.component_instance(), &callback_context)
{
info!( info!(
"Failed to register lock callback '{}': {err}", "Failed to register lock callback '{}': {err}",
callback.name() callback.name()
); );
} else { } else if callback.should_apply(&callback_context) {
info!("Registered lock callback '{}'", callback.name()); info!("Registered lock callback '{}'", callback.name());
}
} else { } else {
info!( info!(
"Skipping callback '{}' due to selector filter (output {:?})", "Skipping callback '{}' due to selector filter (output {:?})",
@ -156,15 +175,35 @@ impl ActiveLockSurface {
} }
pub fn apply_callback(&self, callback: &LockCallback) { pub fn apply_callback(&self, callback: &LockCallback) {
if let Some(component) = self.component.as_ref() { let Some(component) = self.component.as_ref() else {
if let Err(err) = callback.apply_to(component.component_instance()) { 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!( info!(
"Failed to register lock callback '{}': {err}", "Failed to register lock callback '{}': {err}",
callback.name() callback.name()
); );
} }
} }
}
fn scaling_mode(&self) -> LockScalingMode { fn scaling_mode(&self) -> LockScalingMode {
if self.surface.has_fractional_scale() && self.surface.has_viewport() { if self.surface.has_fractional_scale() && self.surface.has_viewport() {

View file

@ -8,6 +8,9 @@ use crate::wayland::globals::context::GlobalContext;
use crate::wayland::managed_proxies::{ManagedWlKeyboard, ManagedWlPointer}; use crate::wayland::managed_proxies::{ManagedWlKeyboard, ManagedWlPointer};
use crate::wayland::outputs::{OutputManager, OutputMapping}; use crate::wayland::outputs::{OutputManager, OutputMapping};
use crate::wayland::session_lock::lock_context::SessionLockContext; use crate::wayland::session_lock::lock_context::SessionLockContext;
use crate::wayland::session_lock::manager::callbacks::{
create_lock_callback, create_lock_callback_with_output_filter,
};
use crate::wayland::session_lock::{LockCallback, OutputFilter, SessionLockManager}; use crate::wayland::session_lock::{LockCallback, OutputFilter, SessionLockManager};
use layer_shika_domain::entities::output_registry::OutputRegistry; use layer_shika_domain::entities::output_registry::OutputRegistry;
use layer_shika_domain::value_objects::handle::SurfaceHandle; use layer_shika_domain::value_objects::handle::SurfaceHandle;
@ -138,7 +141,7 @@ impl AppState {
callback_name: impl Into<String>, callback_name: impl Into<String>,
handler: SessionLockCallback, handler: SessionLockCallback,
) { ) {
let callback = LockCallback::new(callback_name, handler); let callback = create_lock_callback(callback_name, handler);
if let Some(manager) = self.lock_manager.as_mut() { if let Some(manager) = self.lock_manager.as_mut() {
manager.register_callback(callback.clone()); manager.register_callback(callback.clone());
} }
@ -151,7 +154,13 @@ impl AppState {
handler: SessionLockCallback, handler: SessionLockCallback,
filter: OutputFilter, filter: OutputFilter,
) { ) {
let callback = LockCallback::with_filter(callback_name, handler, filter); let callback = create_lock_callback_with_output_filter(
callback_name,
handler,
move |component_name, output_handle, output_info, primary, active| {
filter(component_name, output_handle, output_info, primary, active)
},
);
if let Some(manager) = self.lock_manager.as_mut() { if let Some(manager) = self.lock_manager.as_mut() {
manager.register_callback(callback.clone()); manager.register_callback(callback.clone());
} }