aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2023-09-21 13:48:32 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2023-09-21 13:48:50 +0400
commit109668fa30bf65e56a2723ff29bcadc3e9a6e4ca (patch)
treed95fbf3bdb3c2c14683a34d8bb7203b7dae4820d /src
parentcfa73c153cc6ae2f1c21dcbbc8e755b265babbd2 (diff)
downloadniri-109668fa30bf65e56a2723ff29bcadc3e9a6e4ca.tar.gz
niri-109668fa30bf65e56a2723ff29bcadc3e9a6e4ca.tar.bz2
niri-109668fa30bf65e56a2723ff29bcadc3e9a6e4ca.zip
Add output configuration & integer scaling support
Diffstat (limited to 'src')
-rw-r--r--src/backend/tty.rs16
-rw-r--r--src/backend/winit.rs14
-rw-r--r--src/config.rs27
-rw-r--r--src/layout.rs23
-rw-r--r--src/niri.rs37
5 files changed, 93 insertions, 24 deletions
diff --git a/src/backend/tty.rs b/src/backend/tty.rs
index 9f126507..bce16ff0 100644
--- a/src/backend/tty.rs
+++ b/src/backend/tty.rs
@@ -21,7 +21,7 @@ use smithay::backend::session::libseat::LibSeatSession;
use smithay::backend::session::{Event as SessionEvent, Session};
use smithay::backend::udev::{self, UdevBackend, UdevEvent};
use smithay::desktop::utils::OutputPresentationFeedback;
-use smithay::output::{Mode, Output, OutputModeSource, PhysicalProperties, Subpixel};
+use smithay::output::{Mode, Output, OutputModeSource, PhysicalProperties, Subpixel, Scale};
use smithay::reexports::calloop::{Dispatcher, LoopHandle, RegistrationToken};
use smithay::reexports::drm::control::{
connector, crtc, Mode as DrmMode, ModeFlags, ModeTypeFlags,
@@ -500,6 +500,15 @@ impl Tty {
);
debug!("connecting connector: {output_name}");
+ let config = self
+ .config
+ .borrow()
+ .outputs
+ .iter()
+ .find(|o| o.name == output_name)
+ .cloned()
+ .unwrap_or_default();
+
let device = self.output_device.as_mut().unwrap();
let mut mode = connector.modes().get(0);
@@ -534,6 +543,9 @@ impl Tty {
.map(|info| (info.manufacturer, info.model))
.unwrap_or_else(|| ("Unknown".into(), "Unknown".into()));
+ let scale = config.scale.clamp(0.1, 10.);
+ let scale = scale.max(1.).round() as i32;
+
let output = Output::new(
output_name.clone(),
PhysicalProperties {
@@ -544,7 +556,7 @@ impl Tty {
},
);
let wl_mode = Mode::from(*mode);
- output.change_current_state(Some(wl_mode), None, None, Some((0, 0).into()));
+ output.change_current_state(Some(wl_mode), None, Some(Scale::Integer(scale)), None);
output.set_preferred(wl_mode);
output.user_data().insert_if_missing(|| TtyOutputState {
diff --git a/src/backend/winit.rs b/src/backend/winit.rs
index 9f591e71..99cfe7db 100644
--- a/src/backend/winit.rs
+++ b/src/backend/winit.rs
@@ -8,7 +8,7 @@ use smithay::backend::renderer::damage::OutputDamageTracker;
use smithay::backend::renderer::gles::GlesRenderer;
use smithay::backend::renderer::{DebugFlags, Renderer};
use smithay::backend::winit::{self, WinitError, WinitEvent, WinitGraphicsBackend};
-use smithay::output::{Mode, Output, PhysicalProperties, Subpixel};
+use smithay::output::{Mode, Output, PhysicalProperties, Scale, Subpixel};
use smithay::reexports::calloop::timer::{TimeoutAction, Timer};
use smithay::reexports::calloop::LoopHandle;
use smithay::reexports::wayland_protocols::wp::presentation_time::server::wp_presentation_feedback;
@@ -38,6 +38,16 @@ impl Winit {
.with_title("niri");
let (backend, mut winit_event_loop) = winit::init_from_builder(builder).unwrap();
+ let output_config = config
+ .borrow()
+ .outputs
+ .iter()
+ .find(|o| o.name == "winit")
+ .cloned()
+ .unwrap_or_default();
+ let scale = output_config.scale.clamp(0.1, 10.);
+ let scale = scale.max(1.).round() as i32;
+
let mode = Mode {
size: backend.window_size().physical_size,
refresh: 60_000,
@@ -55,8 +65,8 @@ impl Winit {
output.change_current_state(
Some(mode),
Some(Transform::Flipped180),
+ Some(Scale::Integer(scale)),
None,
- Some((0, 0).into()),
);
output.set_preferred(mode);
diff --git a/src/config.rs b/src/config.rs
index 50ea2451..88773fd3 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -11,6 +11,8 @@ use smithay::input::keyboard::Keysym;
pub struct Config {
#[knuffel(child, default)]
pub input: Input,
+ #[knuffel(children(name = "output"))]
+ pub outputs: Vec<Output>,
#[knuffel(child, default)]
pub binds: Binds,
#[knuffel(child, default)]
@@ -62,6 +64,23 @@ pub struct Touchpad {
pub accel_speed: f64,
}
+#[derive(knuffel::Decode, Debug, Clone, PartialEq)]
+pub struct Output {
+ #[knuffel(argument)]
+ pub name: String,
+ #[knuffel(child, unwrap(argument), default = 1.)]
+ pub scale: f64,
+}
+
+impl Default for Output {
+ fn default() -> Self {
+ Self {
+ name: String::new(),
+ scale: 1.,
+ }
+ }
+}
+
#[derive(knuffel::Decode, Debug, Default, PartialEq, Eq)]
pub struct Binds(#[knuffel(children)] pub Vec<Bind>);
@@ -263,6 +282,10 @@ mod tests {
}
}
+ output "eDP-1" {
+ scale 2.0
+ }
+
binds {
Mod+T { spawn "alacritty"; }
Mod+Q { close-window; }
@@ -293,6 +316,10 @@ mod tests {
accel_speed: 0.2,
},
},
+ outputs: vec![Output {
+ name: "eDP-1".to_owned(),
+ scale: 2.,
+ }],
binds: Binds(vec![
Bind {
key: Key {
diff --git a/src/layout.rs b/src/layout.rs
index f7f00b46..2c0ef30f 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -1231,6 +1231,7 @@ impl Monitor<Window> {
&self,
renderer: &mut GlesRenderer,
) -> Vec<MonitorRenderElement<GlesRenderer>> {
+ let output_scale = Scale::from(self.output.current_scale().fractional_scale());
let output_transform = self.output.current_transform();
let output_mode = self.output.current_mode().unwrap();
let output_size = output_transform.transform_size(output_mode.size);
@@ -1251,7 +1252,7 @@ impl Monitor<Window> {
Some(RelocateRenderElement::from_element(
CropRenderElement::from_element(
elem,
- 1.,
+ output_scale,
Rectangle::from_loc_and_size((0, 0), output_size),
)?,
(0, -offset),
@@ -1262,7 +1263,7 @@ impl Monitor<Window> {
Some(RelocateRenderElement::from_element(
CropRenderElement::from_element(
elem,
- 1.,
+ output_scale,
Rectangle::from_loc_and_size((0, 0), output_size),
)?,
(0, -offset + output_size.h),
@@ -1279,7 +1280,7 @@ impl Monitor<Window> {
Some(RelocateRenderElement::from_element(
CropRenderElement::from_element(
elem,
- 1.,
+ output_scale,
Rectangle::from_loc_and_size((0, 0), output_size),
)?,
(0, 0),
@@ -1823,6 +1824,14 @@ impl Workspace<Window> {
return vec![];
}
+ // FIXME: workspaces should probably cache their last used scale so they can be correctly
+ // rendered even with no outputs connected.
+ let output_scale = self
+ .output
+ .as_ref()
+ .map(|o| Scale::from(o.current_scale().fractional_scale()))
+ .unwrap_or(Scale::from(1.));
+
let mut rv = vec![];
let view_pos = self.view_pos();
@@ -1840,8 +1849,8 @@ impl Workspace<Window> {
}
rv.extend(active_win.render_elements(
renderer,
- win_pos.to_physical(1),
- Scale::from(1.),
+ win_pos.to_physical_precise_round(output_scale),
+ output_scale,
1.,
));
@@ -1862,8 +1871,8 @@ impl Workspace<Window> {
rv.extend(win.render_elements(
renderer,
- win_pos.to_physical(1),
- Scale::from(1.),
+ win_pos.to_physical_precise_round(output_scale),
+ output_scale,
1.,
));
}
diff --git a/src/niri.rs b/src/niri.rs
index 100c388a..0ae5e096 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -799,6 +799,7 @@ impl Niri {
renderer: &mut GlesRenderer,
output: &Output,
) -> Vec<OutputRenderElements<GlesRenderer>> {
+ let output_scale = Scale::from(output.current_scale().fractional_scale());
let output_pos = self.global_space.output_geometry(output).unwrap().loc;
let pointer_pos = self.seat.get_pointer().unwrap().current_location() - output_pos.to_f64();
@@ -825,7 +826,7 @@ impl Niri {
} else {
default_hotspot
};
- let pointer_pos = (pointer_pos - hotspot.to_f64()).to_physical_precise_round(1.);
+ let pointer_pos = (pointer_pos - hotspot.to_f64()).to_physical_precise_round(output_scale);
let mut pointer_elements = match &self.cursor_image {
CursorImageStatus::Hidden => vec![],
@@ -843,7 +844,7 @@ impl Niri {
renderer,
surface,
pointer_pos,
- 1.,
+ output_scale,
1.,
Kind::Cursor,
),
@@ -854,7 +855,7 @@ impl Niri {
renderer,
dnd_icon,
pointer_pos,
- 1.,
+ output_scale,
1.,
Kind::Unspecified,
));
@@ -871,6 +872,8 @@ impl Niri {
) -> Vec<OutputRenderElements<GlesRenderer>> {
let _span = tracy_client::span!("Niri::render");
+ let output_scale = Scale::from(output.current_scale().fractional_scale());
+
// Get monitor elements.
let mon = self.monitor_set.monitor_for_output(output).unwrap();
let monitor_elements = mon.render_elements(renderer);
@@ -901,8 +904,8 @@ impl Niri {
surface
.render_elements(
renderer,
- loc.to_physical_precise_round(1.),
- Scale::from(1.),
+ loc.to_physical_precise_round(output_scale),
+ output_scale,
1.,
)
.into_iter()
@@ -926,8 +929,8 @@ impl Niri {
surface
.render_elements(
renderer,
- loc.to_physical_precise_round(1.),
- Scale::from(1.),
+ loc.to_physical_precise_round(output_scale),
+ output_scale,
1.,
)
.into_iter()
@@ -1084,6 +1087,7 @@ impl Niri {
let _span = tracy_client::span!("Niri::send_for_screen_cast");
let size = output.current_mode().unwrap().size;
+ let scale = Scale::from(output.current_scale().fractional_scale());
for cast in &mut self.casts {
if !cast.is_active.get() {
@@ -1119,7 +1123,7 @@ impl Niri {
let dmabuf = cast.dmabufs.borrow()[&fd].clone();
// FIXME: Hidden / embedded / metadata cursor
- render_to_dmabuf(backend.renderer(), dmabuf, size, elements).unwrap();
+ render_to_dmabuf(backend.renderer(), dmabuf, size, scale, elements).unwrap();
let maxsize = data.as_raw().maxsize;
let chunk = data.chunk_mut();
@@ -1139,8 +1143,9 @@ impl Niri {
let _span = tracy_client::span!("Niri::screenshot");
let size = output.current_mode().unwrap().size;
+ let scale = Scale::from(output.current_scale().fractional_scale());
let elements = self.render(renderer, output, true);
- let pixels = render_to_vec(renderer, size, &elements)?;
+ let pixels = render_to_vec(renderer, size, scale, &elements)?;
let path = make_screenshot_path().context("error making screenshot path")?;
debug!("saving screenshot to {path:?}");
@@ -1174,6 +1179,7 @@ impl Niri {
let outputs: Vec<_> = self.global_space.outputs().cloned().collect();
for output in outputs {
let geom = self.global_space.output_geometry(&output).unwrap();
+ // FIXME: this does not work when outputs can have non-1 scale.
let geom = geom.to_physical(1);
size.w = max(size.w, geom.loc.x + geom.size.w);
@@ -1185,7 +1191,8 @@ impl Niri {
}));
}
- let pixels = render_to_vec(renderer, size, &elements)?;
+ // FIXME: scale.
+ let pixels = render_to_vec(renderer, size, Scale::from(1.), &elements)?;
let path = make_screenshot_path().context("error making screenshot path")?;
debug!("saving screenshot to {path:?}");
@@ -1232,6 +1239,7 @@ impl ClientData for ClientState {
fn render_and_download(
renderer: &mut GlesRenderer,
size: Size<i32, Physical>,
+ scale: Scale<f64>,
elements: &[impl RenderElement<GlesRenderer>],
) -> anyhow::Result<GlesMapping> {
let _span = tracy_client::span!("render_and_download");
@@ -1255,7 +1263,7 @@ fn render_and_download(
for element in elements.iter().rev() {
let src = element.src();
- let dst = element.geometry(Scale::from(1.));
+ let dst = element.geometry(scale);
element
.draw(&mut frame, src, dst, &[output_rect])
.context("error drawing element")?;
@@ -1273,11 +1281,13 @@ fn render_and_download(
fn render_to_vec(
renderer: &mut GlesRenderer,
size: Size<i32, Physical>,
+ scale: Scale<f64>,
elements: &[impl RenderElement<GlesRenderer>],
) -> anyhow::Result<Vec<u8>> {
let _span = tracy_client::span!("render_to_vec");
- let mapping = render_and_download(renderer, size, elements).context("error rendering")?;
+ let mapping =
+ render_and_download(renderer, size, scale, elements).context("error rendering")?;
let copy = renderer
.map_texture(&mapping)
.context("error mapping texture")?;
@@ -1288,6 +1298,7 @@ fn render_to_dmabuf(
renderer: &mut GlesRenderer,
dmabuf: Dmabuf,
size: Size<i32, Physical>,
+ scale: Scale<f64>,
elements: &[OutputRenderElements<GlesRenderer>],
) -> anyhow::Result<()> {
let _span = tracy_client::span!("render_to_dmabuf");
@@ -1305,7 +1316,7 @@ fn render_to_dmabuf(
for element in elements.iter().rev() {
let src = element.src();
- let dst = element.geometry(Scale::from(1.));
+ let dst = element.geometry(scale);
element
.draw(&mut frame, src, dst, &[output_rect])
.context("error drawing element")?;