atagen

monolith

public
Star0
Watch0

Commit defc3c408cd3

tarball

atagen <boss@atagen.co>2026-10-19 09:35 UTC

3 files changed+14-4
scene: keep a window's opacity rule on its close ghost

Ghost carried only the last frame, so a window with an `opacity` rule jumped to full opacity while it faded out.
Modified file: crates/monolith/src/anim.rs+1 additions
@@ -29,6 +29,7 @@ pub struct Ghost {
2929 /// Fades where it is for one phase instead of shrinking in the plan,
3030 /// like a dismissed scratchpad.
3131 pub fixed: Option<Rect>,
32+ pub opacity: f32,
3233 }
3334
3435 struct Track {
Modified file: crates/monolith/src/scene.rs+7 additions−2 deletions
@@ -166,6 +166,7 @@ pub fn build(
166166 frame,
167167 r,
168168 anim.ghost_effect(g, now),
169+ g.opacity,
169170 deco,
170171 scale,
171172 ));
@@ -213,6 +214,7 @@ pub fn build(
213214 frame,
214215 r,
215216 anim.ghost_effect(g, now),
217+ g.opacity,
216218 deco,
217219 scale,
218220 ));
@@ -564,6 +566,7 @@ fn ghost_element(
564566 frame: &LastFrame,
565567 r: Rect,
566568 effect: Effect,
569+ opacity: f32,
567570 deco: &Decoration,
568571 scale: f64,
569572 ) -> Option<Draw> {
@@ -581,14 +584,16 @@ fn ghost_element(
581584 .to_logical(frame.scale, frame.transform)
582585 .to_f64();
583586 let src = src.to_buffer(f64::from(frame.scale), frame.transform, &bounds);
584- let ghost = Draw::Texture(PlacedTexture::new(
587+ let mut placed = PlacedTexture::new(
585588 &frame.texture,
586589 frame.transform,
587590 src,
588591 at,
589592 size,
590593 Some(effect),
591- ));
594+ );
595+ placed.alpha = opacity;
596+ let ghost = Draw::Texture(placed);
592597 Some(match corner_clip(r, deco, scale) {
593598 Some(clip) => Draw::Clipped(ClipElement::new(ghost, clip)),
594599 None => ghost,
Modified file: crates/monolith/src/windows.rs+6 additions−2 deletions
@@ -411,7 +411,8 @@ impl State {
411411 let state = self.wm.remove(id);
412412 if let Some(state) = &state {
413413 self.wm.space.unmap_elem(&state.window);
414- self.leave_ghost(id, &state.window);
414+ let opacity = state.rule.opacity.unwrap_or(1.0);
415+ self.leave_ghost(id, &state.window, opacity);
415416 }
416417 self.wm.layout.remove_window(id);
417418 self.apply_layout();
@@ -420,7 +421,7 @@ impl State {
420421
421422 /// Keeps a visible tiled window's last frame shrinking to its seed while
422423 /// its neighbours close over it.
423- fn leave_ghost(&mut self, id: WindowId, window: &Window) {
424+ fn leave_ghost(&mut self, id: WindowId, window: &Window, opacity: f32) {
424425 let Some(o) = self.wm.layout.window(id).and_then(|w| w.output) else {
425426 return;
426427 };
@@ -450,6 +451,7 @@ impl State {
450451 seed: seed.rect,
451452 born: now_ns(),
452453 fixed: None,
454+ opacity,
453455 });
454456 }
455457 }
@@ -460,6 +462,7 @@ impl State {
460462 let Some(window) = self.wm.window(id).cloned() else {
461463 return;
462464 };
465+ let opacity = self.wm.get(id).and_then(|s| s.rule.opacity).unwrap_or(1.0);
463466 if let Some(frame) = self.last_frame(&window) {
464467 self.wm.last_frames.insert(id, frame);
465468 self.wm.anim.add_ghost(Ghost {
@@ -468,6 +471,7 @@ impl State {
468471 seed: rect,
469472 born: now_ns(),
470473 fixed: Some(rect),
474+ opacity,
471475 });
472476 }
473477 }