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 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<
dyn Fn(
&str,
@ -15,66 +107,64 @@ pub type OutputFilter = Rc<
) -> bool,
>;
#[derive(Clone)]
pub struct LockCallback {
name: String,
handler: LockCallbackHandler,
filter: Option<OutputFilter>,
pub fn create_lock_callback(name: impl Into<String>, handler: CallbackHandler) -> LockCallback {
LockCallbackEntry::new(name, handler)
}
impl LockCallback {
pub fn new(name: impl Into<String>, handler: LockCallbackHandler) -> Self {
Self {
name: name.into(),
handler,
filter: None,
}
}
pub fn with_filter(
pub fn create_lock_callback_with_output_filter<F>(
name: impl Into<String>,
handler: LockCallbackHandler,
filter: OutputFilter,
) -> Self {
Self {
name: name.into(),
handler,
filter: Some(filter),
}
}
pub fn should_apply(
&self,
component_name: &str,
output_handle: OutputHandle,
output_info: Option<&OutputInfo>,
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,
handler: CallbackHandler,
output_filter: F,
) -> LockCallback
where
F: Fn(
&str,
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 apply_to(&self, component: &ComponentInstance) -> Result<()> {
let handler = Rc::clone(&self.handler);
component
.set_callback(&self.name, move |args| handler(args))
.map_err(|e| LayerShikaError::InvalidInput {
message: format!("Failed to register callback '{}': {e}", self.name),
})
}
pub const fn name(&self) -> &String {
&self.name
pub trait LockCallbackExt {
fn apply_to_component(&self, component: &ComponentInstance) -> Result<()>;
fn apply_with_context(
&self,
component: &ComponentInstance,
context: &LockCallbackContext,
) -> Result<()>;
}
impl LockCallbackExt for LockCallbackEntry {
fn apply_to_component(&self, component: &ComponentInstance) -> Result<()> {
let handler = Rc::clone(self.handler());
component
.set_callback(self.name(), move |args| handler(args))
.map_err(|e| LayerShikaError::InvalidInput {
message: format!("Failed to register callback '{}': {e}", self.name()),
})
}
fn apply_with_context(
&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::rendering::femtovg::main_window::FemtoVGWindow;
use crate::rendering::femtovg::renderable_window::RenderableWindow;
@ -51,6 +52,11 @@ pub struct ActiveLockSurface {
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 {
@ -61,6 +67,11 @@ impl ActiveLockSurface {
window,
component: None,
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<()> {
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) => {
@ -103,22 +119,25 @@ impl ActiveLockSurface {
self.window
.window()
.dispatch_event(WindowEvent::WindowActiveChanged(true));
for callback in &context.callbacks {
if callback.should_apply(
&context.component_name,
let callback_context = LockCallbackContext::new(
context.component_name.clone(),
context.output_handle,
context.output_info.as_ref(),
context.output_info.clone(),
context.primary_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!(
"Failed to register lock callback '{}': {err}",
callback.name()
);
} else {
} else if callback.should_apply(&callback_context) {
info!("Registered lock callback '{}'", callback.name());
}
} else {
info!(
"Skipping callback '{}' due to selector filter (output {:?})",
@ -156,15 +175,35 @@ impl ActiveLockSurface {
}
pub fn apply_callback(&self, callback: &LockCallback) {
if let Some(component) = self.component.as_ref() {
if let Err(err) = callback.apply_to(component.component_instance()) {
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() {

View file

@ -8,6 +8,9 @@ use crate::wayland::globals::context::GlobalContext;
use crate::wayland::managed_proxies::{ManagedWlKeyboard, ManagedWlPointer};
use crate::wayland::outputs::{OutputManager, OutputMapping};
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 layer_shika_domain::entities::output_registry::OutputRegistry;
use layer_shika_domain::value_objects::handle::SurfaceHandle;
@ -138,7 +141,7 @@ impl AppState {
callback_name: impl Into<String>,
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() {
manager.register_callback(callback.clone());
}
@ -151,7 +154,13 @@ impl AppState {
handler: SessionLockCallback,
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() {
manager.register_callback(callback.clone());
}