Add window blur, organize Settings, and reduce launcher memory
This commit is contained in:
1 parent
bbc2f226d8
commit
07a8e50f47
17 files changed
+260
-88
No files matched your search
@@ -5,6 +5,7 @@ impl Config {
|
||||
let effect = &self.appearance.focus_effect;
|
||||
Ok(FocusEffectSettings {
|
||||
enabled: effect.enabled,
|
||||
blur: effect.blur,
|
||||
active_opacity: unit_theme_value(effect.active_opacity, "appearance.focus_effect.active_opacity")?,
|
||||
inactive_opacity: unit_theme_value(effect.inactive_opacity, "appearance.focus_effect.inactive_opacity")?,
|
||||
inactive_dim: unit_theme_value(effect.inactive_dim, "appearance.focus_effect.inactive_dim")?,
|
||||
@@ -254,6 +255,7 @@ pub(super) struct AppearanceConfig {
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct FocusEffectSettings {
|
||||
pub enabled: bool,
|
||||
pub blur: bool,
|
||||
pub active_opacity: f64,
|
||||
pub inactive_opacity: f64,
|
||||
pub inactive_dim: f64,
|
||||
@@ -264,6 +266,7 @@ pub struct FocusEffectSettings {
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub(super) struct FocusEffectConfig {
|
||||
pub(super) enabled: bool,
|
||||
pub(super) blur: bool,
|
||||
pub(super) active_opacity: f64,
|
||||
pub(super) inactive_opacity: f64,
|
||||
pub(super) inactive_dim: f64,
|
||||
@@ -274,6 +277,7 @@ impl Default for FocusEffectConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
blur: true,
|
||||
active_opacity: 1.0,
|
||||
inactive_opacity: 1.0,
|
||||
inactive_dim: 0.0,
|
||||
|
||||
@@ -100,6 +100,7 @@ mod tests {
|
||||
fn settings() -> FocusEffectSettings {
|
||||
FocusEffectSettings {
|
||||
enabled: true,
|
||||
blur: true,
|
||||
active_opacity: 1.0,
|
||||
inactive_opacity: 0.8,
|
||||
inactive_dim: 0.2,
|
||||
|
||||
+25
-2
@@ -593,7 +593,8 @@ impl Ferese {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if event.state() == ButtonState::Released && self.tab_buttons.remove(&event.button_code()) {
|
||||
if event.state() == ButtonState::Released && self.consumed_pointer_buttons.remove(&event.button_code())
|
||||
{
|
||||
return;
|
||||
}
|
||||
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
||||
@@ -626,11 +627,33 @@ impl Ferese {
|
||||
return;
|
||||
}
|
||||
|
||||
if event.state() == ButtonState::Pressed
|
||||
&& !pointer.is_grabbed()
|
||||
&& let Some(surface) = self.seat.get_keyboard().and_then(|keyboard| keyboard.current_focus())
|
||||
&& self
|
||||
.space
|
||||
.layer_for_surface(&surface, smithay::desktop::WindowSurfaceType::ALL)
|
||||
.is_some_and(|layer| layer.namespace() == "ferese-launcher")
|
||||
&& !self
|
||||
.layer_under(pointer.current_location())
|
||||
.is_some_and(|(layer, _, _)| layer.wl_surface() == &surface)
|
||||
&& let Some(shell) = self
|
||||
.shell_resources
|
||||
.iter()
|
||||
.filter_map(|shell| shell.upgrade().ok())
|
||||
.find(|shell| shell.version() >= 10)
|
||||
{
|
||||
// Consume both halves of the click before underlying windows or tabs see it.
|
||||
self.consumed_pointer_buttons.insert(event.button_code());
|
||||
shell.toggle_launcher(String::new());
|
||||
return;
|
||||
}
|
||||
|
||||
if event.state() == ButtonState::Pressed
|
||||
&& !pointer.is_grabbed()
|
||||
&& let Some(id) = self.tab_at(pointer.current_location())
|
||||
{
|
||||
self.tab_buttons.insert(event.button_code());
|
||||
self.consumed_pointer_buttons.insert(event.button_code());
|
||||
if event.button_code() == BTN_LEFT {
|
||||
self.activate_managed_window(id);
|
||||
}
|
||||
|
||||
@@ -195,6 +195,12 @@ pub(super) fn grouped_elements(
|
||||
{
|
||||
elements.push(material);
|
||||
}
|
||||
if window.material.is_none()
|
||||
&& let Some(blur) =
|
||||
super::window_blur::window_blur_element(state, renderer, output, window.presentation, corners)
|
||||
{
|
||||
elements.push(blur);
|
||||
}
|
||||
let theme = &state.theme_settings;
|
||||
let (offset_factor, blur_factor, opacity_factor) = window.presentation.shadow_factors();
|
||||
if let Some(shadow) = window_shadow_element(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
mod backdrop;
|
||||
mod capture;
|
||||
mod closing;
|
||||
mod window_blur;
|
||||
mod window_content;
|
||||
pub(crate) use closing::ClosedWindow;
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -20,6 +20,7 @@ pub(super) struct WindowBuffers {
|
||||
pub borders: WindowBorderBuffers,
|
||||
pub dim: WindowBorderBuffers,
|
||||
pub resize_fill: WindowBorderBuffers,
|
||||
pub blur: HashMap<(ErasedContextId, OutputId), super::window_blur::WindowBlur>,
|
||||
pub shadow: WindowShadowBuffers,
|
||||
corner_shape: Option<CornerShape>,
|
||||
thumbnail_shapes: HashMap<OutputId, CornerShape>,
|
||||
@@ -48,6 +49,7 @@ impl RenderResources {
|
||||
buffers.dim.contexts.clear();
|
||||
buffers.resize_fill.contexts.clear();
|
||||
buffers.shadow.contexts.clear();
|
||||
buffers.blur.clear();
|
||||
|
||||
if let Some(snapshot) = &mut buffers.snapshot {
|
||||
snapshot.commit.increment();
|
||||
@@ -101,6 +103,7 @@ impl RenderResources {
|
||||
|
||||
for window in self.windows.values_mut() {
|
||||
window.thumbnail_shapes.remove(&id);
|
||||
window.blur.retain(|(_, output), _| *output != id);
|
||||
}
|
||||
|
||||
for surface in self.surfaces.values_mut() {
|
||||
@@ -167,6 +170,7 @@ impl RenderResources {
|
||||
window.dim.contexts.remove(context);
|
||||
window.resize_fill.contexts.remove(context);
|
||||
window.shadow.contexts.remove(context);
|
||||
window.blur.retain(|(key, _), _| key != context);
|
||||
|
||||
if window
|
||||
.snapshot
|
||||
|
||||
@@ -340,6 +340,12 @@ fn scene_elements(
|
||||
{
|
||||
elements.push(background);
|
||||
}
|
||||
if material_surface.is_none()
|
||||
&& let Some(blur) =
|
||||
super::window_blur::window_blur_element(state, renderer, output, sample.presentation, corners)
|
||||
{
|
||||
elements.push(blur);
|
||||
}
|
||||
if let Some(shadow) = shadow {
|
||||
elements.push(shadow.into());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct WindowBlur {
|
||||
parameters: MaterialParameters,
|
||||
element: BlurRenderElement,
|
||||
}
|
||||
|
||||
pub(super) fn window_blur_element(
|
||||
state: &mut Ferese,
|
||||
renderer: &mut GlesRenderer,
|
||||
output: &Output,
|
||||
presentation: crate::presentation::WindowPresentation,
|
||||
corners: RoundedRect,
|
||||
) -> Option<AnimatedWindowRenderElement> {
|
||||
let radius = state.theme_settings.backdrop_blur;
|
||||
if !state.focus_effect.enabled
|
||||
|| !state.focus_effect.blur
|
||||
|| state.theme_settings.reduce_transparency
|
||||
|| radius <= 0.0
|
||||
|| presentation.focus_alpha <= 0.0
|
||||
|| presentation.focus_alpha >= 1.0
|
||||
|| presentation.alpha() <= 0.0
|
||||
{
|
||||
if let Some(window) = state.render.windows.get_mut(&presentation.id) {
|
||||
window.blur.clear();
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
let mode = output.current_mode()?;
|
||||
let scale = output.current_scale().fractional_scale();
|
||||
let transform = output.current_transform().invert();
|
||||
let output_size = output
|
||||
.current_transform()
|
||||
.transform_size(mode.size)
|
||||
.to_f64()
|
||||
.to_logical(scale)
|
||||
.to_i32_ceil();
|
||||
let geometry = corners.rect.to_f64().to_logical(scale).to_i32_up();
|
||||
let Some(visible) = geometry.intersection(Rectangle::from_size(output_size)) else {
|
||||
if let Some(window) = state.render.windows.get_mut(&presentation.id) {
|
||||
window.blur.clear();
|
||||
}
|
||||
return None;
|
||||
};
|
||||
let sample_geometry = expanded_blur_region(visible, radius.ceil() as i32, output_size);
|
||||
let sample_physical = sample_geometry.to_physical_precise_round(scale);
|
||||
let parameters = MaterialParameters {
|
||||
panel: None,
|
||||
corner_radii: [corners.radius; 4],
|
||||
// Replace the sharp backdrop completely. Window content supplies the
|
||||
// transparency; only the lifecycle animation fades this background.
|
||||
presentation_alpha: presentation.opacity.current.clamp(0.0, 1.0) as f32,
|
||||
background_opacity: 0.0,
|
||||
blur: (radius * scale) as f32,
|
||||
sample_geometry,
|
||||
sample_physical,
|
||||
sample_framebuffer: framebuffer_clip_rect(sample_physical, mode.size, transform),
|
||||
shadow_rect: [0.0; 4],
|
||||
shadow_values: [0.0; 2],
|
||||
shadow_bounds: geometry,
|
||||
geometry,
|
||||
tint: [0.0; 4],
|
||||
generation: 0,
|
||||
opaque: false,
|
||||
visible_framebuffer: framebuffer_clip_rect(corners.rect, mode.size, transform),
|
||||
};
|
||||
let key = (renderer.context_id().erased(), state.output_id(output)?);
|
||||
let program = blur_program(&mut state.render, renderer)?;
|
||||
let buffers = &mut state.render.windows.entry(presentation.id).or_default().blur;
|
||||
let capture_rect = framebuffer_capture_rect(parameters.sample_framebuffer);
|
||||
let capture_size = Size::from((capture_rect[2], capture_rect[3]));
|
||||
if buffers
|
||||
.get(&key)
|
||||
.is_none_or(|cached| cached.element.texture.size() != capture_size)
|
||||
{
|
||||
let texture = match Offscreen::<GlesTexture>::create_buffer(renderer, Fourcc::Abgr8888, capture_size) {
|
||||
Ok(texture) => texture,
|
||||
Err(error) => {
|
||||
tracing::warn!(%error, "window blur allocation failed");
|
||||
buffers.remove(&key);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let element = BlurRenderElement::new(texture, program.0, ¶meters, Arc::new(AtomicBool::new(true)));
|
||||
buffers.insert(
|
||||
key.clone(),
|
||||
WindowBlur {
|
||||
parameters: parameters.clone(),
|
||||
element,
|
||||
},
|
||||
);
|
||||
}
|
||||
let cached = buffers.get_mut(&key)?;
|
||||
if cached.parameters != parameters {
|
||||
cached.element.update(¶meters);
|
||||
cached.parameters = parameters;
|
||||
}
|
||||
Some(cached.element.clone().into())
|
||||
}
|
||||
@@ -467,7 +467,7 @@ pub struct Ferese {
|
||||
pub(crate) tab_indicator: tab_indicator::TabIndicatorState,
|
||||
pub(crate) tab_indicator_settings: crate::config::TabIndicatorSettings,
|
||||
pub(crate) tab_bars: HashMap<WorkspaceId, Vec<ferese_layout::TabBar>>,
|
||||
pub(crate) tab_buttons: HashSet<u32>,
|
||||
pub(crate) consumed_pointer_buttons: HashSet<u32>,
|
||||
pub(crate) focus_history: ferese_core::FocusHistory,
|
||||
pub(crate) focus_cycle: Option<ferese_core::FocusCycle>,
|
||||
column_width_presets: Vec<ColumnWidth>,
|
||||
@@ -771,7 +771,7 @@ impl Ferese {
|
||||
tab_indicator: tab_indicator::TabIndicatorState::default(),
|
||||
tab_indicator_settings: config.tab_indicator,
|
||||
tab_bars: HashMap::new(),
|
||||
tab_buttons: HashSet::new(),
|
||||
consumed_pointer_buttons: HashSet::new(),
|
||||
focus_history: Default::default(),
|
||||
focus_cycle: None,
|
||||
column_width_presets: config.column_width_presets,
|
||||
|
||||
@@ -388,6 +388,7 @@ mod tests {
|
||||
.unwrap();
|
||||
state.focus_effect = crate::config::FocusEffectSettings {
|
||||
enabled: true,
|
||||
blur: true,
|
||||
active_opacity: 0.9,
|
||||
inactive_opacity: 0.6,
|
||||
inactive_dim: 0.2,
|
||||
|
||||
Reference in new issue
Block a user