This has been requested before (I can't find off the bat). I believe one usecase was for a broken monitor with a region of dead pixels on one side. Adding a black bar there would exclude the broken region from display.
Another usecase could be when you need to force a game to 16:9 on an ultrawide screen and you're fine with black bars.
I happened across yet another usecase now: I'm giving a presentation at a place with unfortunate presenter desk placement that obscures part of the screen for the viewers. So the bottom-right corner and edges of the slides are invisible or hard to see for the audience. Adding small bottom and right black bars would allow for fullscreen presentation that would be well visible to everyone.
This should probably be a block like struts {} in an output {}, but it should be called something different to avoid confusion (not sure what it should be called).
I'm also fairly sure that with current Smithay, using black solid color should keep the direct scanout working for a fullscreen client (using appropriate DRM props).
Activity
2Hello! Maybe you're referring to discussion https://github.com/niri-wm/niri/discussions/924 I opened last year? The problem you're describing rang a bell.
I solved it following you advice (I pasted the code below). I remember it working very well, although there was a way to get some stuff above the bar, maybe when dragging a window over to another screen? I don't remember well, I changed laptop in the meantime. It was mostly a non-issue though.
diff --git a/src/niri.rs b/src/niri.rs
index e59de48b3f..875a024ba1 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -490,6 +490,8 @@ pub struct OutputState {
screen_transition: Option<ScreenTransition>,
/// Damage tracker used for the debug damage visualization.
pub debug_damage_tracker: OutputDamageTracker,
+ /// Solid color buffer to always display a column of black pixels on the left of the screen
+ pub bar_buffer: SolidColorBuffer,
}
#[derive(Debug, Default)]
@@ -3088,6 +3090,7 @@ impl Niri {
lock_color_buffer: SolidColorBuffer::new(size, CLEAR_COLOR_LOCKED),
screen_transition: None,
debug_damage_tracker: OutputDamageTracker::from_output(&output),
+ bar_buffer: SolidColorBuffer::new(Size::from((1.0, size.h)), Color32F::BLACK),
};
let rv = self.output_state.insert(output.clone(), state);
assert!(rv.is_none(), "output was already tracked");
@@ -3195,6 +3198,7 @@ impl Niri {
if let Some(state) = self.output_state.get_mut(output) {
state.backdrop_buffer.resize(output_size);
+ state.bar_buffer.resize(Size::from((1.0, output_size.h)));
state.lock_color_buffer.resize(output_size);
if let Some(lock_surface) = &state.lock_surface {
@@ -4329,11 +4333,22 @@ impl Niri {
let output_scale = Scale::from(output.current_scale().fractional_scale());
+ let state = self.output_state.get(output).unwrap();
+ let bar = SolidColorRenderElement::from_buffer(
+ &state.bar_buffer,
+ (0.0, 0.0),
+ 1.,
+ Kind::Unspecified,
+ )
+ .into();
+
// The pointer goes on the top.
let mut elements = vec![];
if include_pointer {
elements = self.pointer_element(renderer, output);
}
+ // Then, the black bar
+ elements.insert(0, bar);
// Next, the screen transition texture.
{
A wayland client that uses layer shells to set exclusive zones could solve this to some extent (as long as it doesn't fight, say, another bar that requests an exclusive zone on the same side)
EDIT: I forgot that fullscreening would ignore the exclusive zones...