Add live config reload, session locking and managed daemons

Refine focus gradients, shell workspace controls and popup motion. Correct floating stacking and preserve client-chosen dialog sizes. Add lock protocol probes and session integration.
This commit is contained in:
Samuel Onoja committed 2026-09-26 19:03:37 +01:00
1 parent b422448d88
commit 672b4e2b60
41 files changed
+2694 -298

No files matched your search

+74 -3
View File
@@ -65,6 +65,9 @@ struct SurfaceEffectsState {
generation: AtomicU64,
role: Mutex<Option<SemanticRole>>,
regions: Mutex<Option<Vec<[i32; 5]>>>,
opacity: Mutex<u32>,
presentation_supported: AtomicBool,
dismissing: AtomicBool,
}
impl SurfaceEffectsState {
@@ -74,6 +77,9 @@ impl SurfaceEffectsState {
generation: AtomicU64::new(0),
role: Mutex::new(None),
regions: Mutex::new(None),
opacity: Mutex::new(1000),
presentation_supported: AtomicBool::new(false),
dismissing: AtomicBool::new(false),
}
}
@@ -103,7 +109,7 @@ impl SurfaceEffectsUserData {
}
pub(crate) fn init_global(display: &DisplayHandle) {
display.create_global::<Ferese, FereseEffectsManagerV1, _>(2, ());
display.create_global::<Ferese, FereseEffectsManagerV1, _>(3, ());
}
pub(crate) fn surface_regions(surface: &WlSurface) -> Option<Vec<[i32; 5]>> {
@@ -197,7 +203,15 @@ impl Dispatch<FereseEffectsManagerV1, ()> for Ferese {
"wl_surface already has a Ferese effects object",
);
} else {
data_init.init(id, SurfaceEffectsUserData::new(surface));
let effects = data_init.init(id, SurfaceEffectsUserData::new(surface.clone()));
with_states(&surface, |states| {
states
.data_map
.get::<SurfaceEffectsState>()
.unwrap()
.presentation_supported
.store(effects.version() >= 3, Ordering::Release)
});
}
}
ferese_effects_manager_v1::Request::Destroy => {}
@@ -221,6 +235,27 @@ impl Dispatch<FereseSurfaceEffectsV1, SurfaceEffectsUserData> for Ferese {
};
match request {
ferese_surface_effects_v1::Request::SetOpacity { opacity } => {
let changed = with_states(&surface, |states| {
let Some(effects) = states.data_map.get::<SurfaceEffectsState>() else {
return false;
};
if effects.dismissing.load(Ordering::Acquire) {
return false;
}
let mut current = effects.opacity.lock().unwrap();
let opacity = opacity.min(1000);
if *current == opacity {
return false;
}
*current = opacity;
effects.generation.fetch_add(1, Ordering::Release);
true
});
if changed {
crate::backends::direct::render_all(state);
}
}
ferese_surface_effects_v1::Request::SetRole { role } => {
let role = match role {
WEnum::Value(ferese_surface_effects_v1::Role::Panel) => SemanticRole::Panel,
@@ -301,11 +336,47 @@ fn detach(surface: &WlSurface) -> bool {
return false;
};
let role_changed = effects.set_role(None);
effects.dismissing.store(false, Ordering::Release);
let mut opacity = effects.opacity.lock().unwrap();
let opacity_changed = *opacity != 1000;
*opacity = 1000;
let was_attached = effects.attached.swap(false, Ordering::AcqRel);
role_changed || was_attached
role_changed || was_attached || opacity_changed
})
}
pub(crate) fn surface_opacity(surface: &WlSurface) -> f32 {
with_states(surface, |states| {
states
.data_map
.get::<SurfaceEffectsState>()
.map_or(1.0, |effects| {
*effects.opacity.lock().unwrap() as f32 / 1000.0
})
})
}
pub(crate) fn begin_surface_dismiss(surface: &WlSurface) -> bool {
with_states(surface, |states| {
states
.data_map
.get::<SurfaceEffectsState>()
.is_some_and(|effects| {
effects.presentation_supported.load(Ordering::Acquire)
&& effects.attached.load(Ordering::Acquire)
&& !effects.dismissing.swap(true, Ordering::AcqRel)
})
})
}
pub(crate) fn fade_dismissed_surface(surface: &WlSurface, opacity: f64) {
with_states(surface, |states| {
if let Some(effects) = states.data_map.get::<SurfaceEffectsState>() {
*effects.opacity.lock().unwrap() = (opacity.clamp(0.0, 1.0) * 1000.0).round() as u32;
effects.generation.fetch_add(1, Ordering::Release);
}
});
}
#[cfg(test)]
mod tests {
use super::*;