Commit 39d2db731e01
tarball1 file changed+85-41
@@ -178,16 +178,8 @@ pub fn build(
178178
let effect = anim.effect(id, now);179179
let first = out.len();180180
let opacity = state.rule.opacity.unwrap_or(1.0);181
- window_elements(182
- &mut out,183
- renderer,184
- &state.window,185
- r,186
- effect,187
- gliding,188
- scale,189
- opacity,190
- );181
+ let spot = Spot { r, scale, opacity };182
+ window_elements(&mut out, renderer, &state.window, &spot, effect, gliding);191183
let clip = framed.then(|| corner_clip(r, deco, scale)).flatten();192184
if let Some(clip) = clip {193185
clip_window(&mut out, first, clip);@@ -230,23 +222,20 @@ pub fn build(
230222
/// cropped and one smaller has its last row and column stretched over the231223
/// rest, keeping content aligned with its neighbours. A gliding window is232224
/// scaled instead, so the client resizing mid-glide does not jump.233
-#[expect(clippy::too_many_arguments)]234225
fn window_elements(235226
out: &mut Vec<Draw>,236227
renderer: &mut VulkanRenderer,237228
window: &Window,238
- r: Rect,229
+ spot: &Spot,239230
effect: Option<Effect>,240231
scaled: bool,241
- scale: f64,242
- opacity: f32,243232
) {244
- let Some(((x, y), (w, h))) = pixels(r, scale) else {233
+ let Spot { scale, opacity, .. } = *spot;234
+ let Some(((x, y), (w, h))) = spot.pixels() else {245235
return;246236
};247237
let geo = window.geometry();248
- let inset = geo.loc.to_physical_precise_round::<_, i32>(scale);249
- let drawn: Size<i32, Physical> = geo.size.to_physical_precise_round(scale);238
+ let (inset, drawn) = edges(geo, scale);250239
let loc = Point::<i32, Physical>::from((x - inset.x, y - inset.y));251240
let alpha = effect.map_or(1.0, |e| e.progress) * opacity;252241
let elems: Vec<WaylandSurfaceRenderElement<VulkanRenderer>> = match window.toplevel() {@@ -261,16 +250,7 @@ fn window_elements(
261250
None => window.render_elements(renderer, loc, Scale::from(scale), alpha),262251
};263252
if let Some(effect) = effect {264
- effect_elements(265
- out,266
- renderer,267
- window,268
- elems,269
- ((x, y), (w, h)),270
- effect,271
- scale,272
- opacity,273
- );253
+ effect_elements(out, renderer, window, elems, spot, effect);274254
return;275255
}276256
if scaled && drawn.w > 0 && drawn.h > 0 {@@ -301,31 +281,43 @@ fn window_elements(
301281
return;302282
};303283
let context = renderer.context_id();304
- let Some((tex, buffer_scale, transform, view)) = with_renderer_surface_state(&root, |s| {305
- let texture = s.texture::<VulkanTexture>(context.clone())?.clone();306
- Some((texture, s.buffer_scale(), s.buffer_transform(), s.view()?))307
- })308
- .flatten() else {284
+ let Some((tex, buffer_scale, transform, view, commit)) =285
+ with_renderer_surface_state(&root, |s| {286
+ let texture = s.texture::<VulkanTexture>(context.clone())?.clone();287
+ Some((288
+ texture,289
+ s.buffer_scale(),290
+ s.buffer_transform(),291
+ s.view()?,292
+ s.current_commit(),293
+ ))294
+ })295
+ .flatten()296
+ else {309297
return;310298
};299
+ let ids = window.user_data().get_or_insert_threadsafe(StripIds::new);311300
let (gw, gh) = (drawn.w, drawn.h);312301
let (cw, ch) = (w.min(gw), h.min(gh));313302
let ratio = source_ratio(&view);314303
let geo_src = to_source(&view, geo.to_f64());315304
let (gx, gy) = (geo_src.loc.x, geo_src.loc.y);316
- let mut strip = |src: Rectangle<f64, Logical>, at: (i32, i32), size: (i32, i32)| {305
+ let mut strip = |id: &Id, src: Rectangle<f64, Logical>, at: (i32, i32), size: (i32, i32)| {317306
if size.0 >= 1 && size.1 >= 1 {318307
let bounds = tex.size().to_logical(buffer_scale, transform).to_f64();319308
let src = src.to_buffer(f64::from(buffer_scale), transform, &bounds);320
- out.push(Draw::Texture(PlacedTexture::new(321
- &tex, transform, src, at, size, None,322
- )));309
+ let mut placed = PlacedTexture::new(&tex, transform, src, at, size, None);310
+ placed.id = id.clone();311
+ placed.commit = commit;312
+ placed.alpha = opacity;313
+ out.push(Draw::Texture(placed));323314
}324315
};325316
let pixel = 1.0 / f64::from(buffer_scale);326317
let right = gx + geo_src.size.w - pixel;327318
let bottom = gy + geo_src.size.h - pixel;328319
strip(320
+ &ids.right,329321
Rectangle::new(330322
(right, gy).into(),331323
(pixel, f64::from(ch) / scale * ratio.1).into(),@@ -334,6 +326,7 @@ fn window_elements(
334326
(w - gw, ch),335327
);336328
strip(329
+ &ids.bottom,337330
Rectangle::new(338331
(gx, bottom).into(),339332
(f64::from(cw) / scale * ratio.0, pixel).into(),@@ -342,6 +335,7 @@ fn window_elements(
342335
(cw, h - gh),343336
);344337
strip(338
+ &ids.corner,345339
Rectangle::new((right, bottom).into(), (pixel, pixel).into()),346340
(x + gw, y + gh),347341
(w - gw, h - gh),@@ -428,17 +422,18 @@ fn border_width(deco: &Decoration, scale: f64) -> i32 {
428422
429423
/// A window in a spawn transition. Its root surface goes through the effect430424
/// shader, clamped to fill its rect, and its subsurfaces fade with it.431
-#[expect(clippy::too_many_arguments)]432425
fn effect_elements(433426
out: &mut Vec<Draw>,434427
renderer: &mut VulkanRenderer,435428
window: &Window,436429
elems: Vec<WaylandSurfaceRenderElement<VulkanRenderer>>,437
- (at, size): ((i32, i32), (i32, i32)),430
+ spot: &Spot,438431
effect: Effect,439
- scale: f64,440
- opacity: f32,441432
) {433
+ let Spot { scale, opacity, .. } = *spot;434
+ let Some((at, size)) = spot.pixels() else {435
+ return;436
+ };442437
let Some(root) = crate::wm::root(window) else {443438
return;444439
};@@ -474,10 +469,54 @@ fn effect_elements(
474469
}475470
}476471
472
+/// Where and how a window is drawn, in logical units and at an output scale.473
+struct Spot {474
+ r: Rect,475
+ scale: f64,476
+ opacity: f32,477
+}478
+479
+impl Spot {480
+ fn pixels(&self) -> Option<((i32, i32), (i32, i32))> {481
+ pixels(self.r, self.scale)482
+ }483
+}484
+485
+/// The inset and size of a window geometry in physical pixels, rounding both486
+/// edges so the size agrees with the rect `pixels` snaps a window to.487
+fn edges(geo: Rectangle<i32, Logical>, scale: f64) -> (Point<i32, Physical>, Size<i32, Physical>) {488
+ let round = |v: i32| (f64::from(v) * scale).round() as i32;489
+ let (x, y) = (round(geo.loc.x), round(geo.loc.y));490
+ let size = (491
+ round(geo.loc.x + geo.size.w) - x,492
+ round(geo.loc.y + geo.size.h) - y,493
+ );494
+ ((x, y).into(), size.into())495
+}496
+497
+/// The ids of the strips drawn past a window that is smaller than its rect,498
+/// kept so an unchanged window does not damage its area every frame.499
+struct StripIds {500
+ right: Id,501
+ bottom: Id,502
+ corner: Id,503
+}504
+505
+impl StripIds {506
+ fn new() -> Self {507
+ Self {508
+ right: Id::new(),509
+ bottom: Id::new(),510
+ corner: Id::new(),511
+ }512
+ }513
+}514
+477515
/// A texture at a physical rectangle, drawn plainly or through the478516
/// transition hook in the effect shader.479517
pub struct PlacedTexture {480518
id: Id,519
+ commit: CommitCounter,481520
texture: VulkanTexture,482521
src: Rectangle<f64, Buffer>,483522
geometry: Rectangle<i32, Physical>,@@ -497,6 +536,7 @@ impl PlacedTexture {
497536
) -> Self {498537
Self {499538
id: Id::new(),539
+ commit: CommitCounter::default(),500540
texture: texture.clone(),501541
src,502542
geometry: Rectangle::new(at.into(), size.into()),@@ -513,13 +553,17 @@ impl Element for PlacedTexture {
513553
}514554
515555
fn current_commit(&self) -> CommitCounter {516
- CommitCounter::default()556
+ self.commit517557
}518558
519559
fn src(&self) -> Rectangle<f64, Buffer> {520560
self.src521561
}522562
563
+ fn alpha(&self) -> f32 {564
+ self.alpha565
+ }566
+523567
fn geometry(&self, _scale: Scale<f64>) -> Rectangle<i32, Physical> {524568
self.geometry525569
}