Commit eacaaa02eca5
tarball4 files changed+41-46
@@ -34,6 +34,9 @@ focused = "#88bfd1"
3434
unfocused = "#3b4252"3535
# A window asking for attention that is not focused.3636
urgent = "#ebcb8b"37
+# A window extended over others in its container.38
+extended = "#5e4b6e"39
+extended-focused = "#b48ead"3740
3841
[output]3942
# Variable refresh rate on outputs that support it, off, on, or fullscreen.@@ -191,7 +191,7 @@ pub enum Vrr {
191191
}192192
193193
#[derive(Deserialize, Debug, Clone, PartialEq)]194
-#[serde(default, deny_unknown_fields)]194
+#[serde(default, deny_unknown_fields, rename_all = "kebab-case")]195195
pub struct Decoration {196196
/// Border width in logical pixels, drawn in the gap around each window.197197
pub border: u32,@@ -199,6 +199,8 @@ pub struct Decoration {
199199
pub focused: Color,200200
pub unfocused: Color,201201
pub urgent: Color,202
+ pub extended: Color,203
+ pub extended_focused: Color,202204
}203205
204206
/// Corner radii in logical pixels, top left, top right, bottom right and@@ -234,6 +236,8 @@ impl Default for Decoration {
234236
focused: Color::rgb(0x88, 0xbf, 0xd1),235237
unfocused: Color::rgb(0x3b, 0x42, 0x52),236238
urgent: Color::rgb(0xeb, 0xcb, 0x8b),239
+ extended: Color::rgb(0x5e, 0x4b, 0x6e),240
+ extended_focused: Color::rgb(0xb4, 0x8e, 0xad),237241
}238242
}239243
}@@ -185,32 +185,26 @@ pub fn build(
185185
clip_window(&mut out, first, clip);186186
}187187
if framed && deco.border > 0 {188
+ let extended = layout.grouped(id);188189
let color = if focused == Some(id) {189
- deco.focused.0190
+ if extended {191
+ deco.extended_focused.0192
+ } else {193
+ deco.focused.0194
+ }190195
} else if layout.window(id).is_some_and(|w| w.urgent) {191196
deco.urgent.0197
+ } else if extended {198
+ deco.extended.0192199
} else {193200
deco.unfocused.0194201
};195202
let alpha = effect.map_or(1.0, |e| e.progress) * opacity;196
- let b = border_width(deco, scale);197
- let radius = deco.radius.0.into_iter().max().unwrap_or(0);198
- let radius = (f64::from(radius) * scale).round() as i32;199
- let rings = if layout.grouped(id) { 2 } else { 1 };200
- let Some((at, size)) = pixels(r, scale) else {201
- continue;202
- };203
- let window = Rectangle::new(at.into(), size.into());204
- for (k, borders) in state.borders.iter_mut().take(rings).enumerate() {205
- let by = 2 * b * k as i32;206
- let frame = outset_rect(window, by);207
- let reach = if radius > 0 { radius + by } else { 0 };208
- let reach = reach.min(frame.size.w / 2).min(frame.size.h / 2);209
- let first = out.len();210
- border_elements(&mut out, borders, frame, b, reach, color, alpha);211
- if let Some(clip) = clip {212
- ring_borders(&mut out, first, outset(clip, by), b);213
- }203
+ let borders = &mut state.borders;204
+ let first = out.len();205
+ border_elements(&mut out, borders, r, deco, color, alpha, scale);206
+ if let Some(clip) = clip {207
+ ring_borders(&mut out, first, clip, border_width(deco, scale));214208
}215209
}216210
}@@ -355,19 +349,24 @@ fn window_elements(
355349
);356350
}357351
358
-/// Four strips `b` wide just outside `frame`, in the gap, so the client keeps359
-/// its size. With rounded corners they `reach` in by the largest radius, to360
-/// cover the band the ring curves through inside the frame's corners.352
+/// Four strips just outside `r`, in the gap, so the client keeps its size.353
+/// With rounded corners they reach in by the largest radius, to cover the354
+/// band the ring curves through inside the window's corners.361355
fn border_elements(362356
out: &mut Vec<Draw>,363357
borders: &mut Option<[SolidColorBuffer; 4]>,364
- frame: Rectangle<i32, Physical>,365
- b: i32,366
- reach: i32,358
+ r: Rect,359
+ deco: &Decoration,367360
color: [f32; 4],368361
alpha: f32,362
+ scale: f64,369363
) {370
- let (x, y, w, h) = (frame.loc.x, frame.loc.y, frame.size.w, frame.size.h);364
+ let Some(((x, y), (w, h))) = pixels(r, scale) else {365
+ return;366
+ };367
+ let b = border_width(deco, scale);368
+ let reach = (f64::from(deco.radius.0.into_iter().max().unwrap_or(0)) * scale).round() as i32;369
+ let reach = reach.min(w / 2).min(h / 2);371370
let strips = [372371
((x - b, y - b), (w + 2 * b, b + reach)),373372
((x - b, y + h - reach), (w + 2 * b, b + reach)),@@ -670,31 +669,20 @@ fn clip_window(out: &mut [Draw], first: usize, clip: Clip) {
670669
/// Turns the border strips from `first` on into a ring around the window's671670
/// rounded outline.672671
fn ring_borders(out: &mut [Draw], first: usize, window: Clip, b: i32) {672
+ let grow = |r: f32| if r > 0.0 { r + b as f32 } else { 0.0 };673673
let ring = Clip {674
+ rect: Rectangle::new(675
+ window.rect.loc - Point::from((b, b)),676
+ window.rect.size + Size::from((2 * b, 2 * b)),677
+ ),678
+ radii: window.radii.map(grow),674679
ring: b as f32,675
- ..outset(window, b)676680
};677681
for draw in &mut out[first..] {678682
wrap(draw, ring);679683
}680684
}681685
682
-fn outset(clip: Clip, by: i32) -> Clip {683
- let grow = |r: f32| if r > 0.0 { r + by as f32 } else { 0.0 };684
- Clip {685
- rect: outset_rect(clip.rect, by),686
- radii: clip.radii.map(grow),687
- ring: clip.ring,688
- }689
-}690
-691
-fn outset_rect(r: Rectangle<i32, Physical>, by: i32) -> Rectangle<i32, Physical> {692
- Rectangle::new(693
- r.loc - Point::from((by, by)),694
- r.size + Size::from((2 * by, 2 * by)),695
- )696
-}697
-698686
fn wrap(draw: &mut Draw, clip: Clip) {699687
let inner = std::mem::replace(draw, Draw::Clipped(ClipElement::empty()));700688
*draw = Draw::Clipped(ClipElement::new(inner, clip));@@ -99,7 +99,7 @@ pub struct WindowState {
9999
/// A rule sent it somewhere, so activation tokens leave it alone.100100
pub placed_by_rule: bool,101101
pub list_handle: Option<ForeignToplevelHandle>,102
- pub borders: [Option<[SolidColorBuffer; 4]>; 2],102
+ pub borders: Option<[SolidColorBuffer; 4]>,103103
pub app_id: String,104104
pub title: String,105105
/// The title it mapped with, which `initial_title` rules match.@@ -172,7 +172,7 @@ impl Wm {
172172
reclassify: false,173173
placed_by_rule,174174
list_handle: None,175
- borders: [None, None],175
+ borders: None,176176
app_id,177177
initial_title: title.clone(),178178
title,