ui/exit_confirm_dialog: Make fractional-scaling aware

This commit is contained in:
Ivan Molodetskikh 2024-06-09 10:24:17 +03:00
parent 7019172b67
commit 98aea9579f
3 changed files with 51 additions and 45 deletions

10
Cargo.lock generated
View File

@ -2185,6 +2185,7 @@ dependencies = [
"niri-config", "niri-config",
"niri-ipc", "niri-ipc",
"notify-rust", "notify-rust",
"ordered-float",
"pangocairo", "pangocairo",
"pipewire", "pipewire",
"png", "png",
@ -2409,6 +2410,15 @@ dependencies = [
"libredox 0.0.2", "libredox 0.0.2",
] ]
[[package]]
name = "ordered-float"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a76df7075c7d4d01fdcb46c912dd17fba5b60c78ea480b475f2b6ab6f666584e"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "ordered-stream" name = "ordered-stream"
version = "0.2.0" version = "0.2.0"

View File

@ -63,6 +63,7 @@ log = { version = "0.4.21", features = ["max_level_trace", "release_max_level_de
niri-config = { version = "0.1.6", path = "niri-config" } niri-config = { version = "0.1.6", path = "niri-config" }
niri-ipc = { version = "0.1.6", path = "niri-ipc", features = ["clap"] } niri-ipc = { version = "0.1.6", path = "niri-ipc", features = ["clap"] }
notify-rust = { version = "~4.10.0", optional = true } notify-rust = { version = "~4.10.0", optional = true }
ordered-float = "4.2.0"
pangocairo = "0.19.2" pangocairo = "0.19.2"
pipewire = { version = "0.8.0", optional = true } pipewire = { version = "0.8.0", optional = true }
png = "0.17.13" png = "0.17.13"

View File

@ -1,18 +1,19 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use ordered_float::NotNan;
use pangocairo::cairo::{self, ImageSurface}; use pangocairo::cairo::{self, ImageSurface};
use pangocairo::pango::{Alignment, FontDescription}; use pangocairo::pango::{Alignment, FontDescription};
use smithay::backend::renderer::element::memory::{ use smithay::backend::renderer::element::Kind;
MemoryRenderBuffer, MemoryRenderBufferRenderElement,
};
use smithay::backend::renderer::element::utils::{Relocate, RelocateRenderElement};
use smithay::backend::renderer::element::{Element, Kind};
use smithay::output::Output; use smithay::output::Output;
use smithay::reexports::gbm::Format as Fourcc; use smithay::reexports::gbm::Format as Fourcc;
use smithay::utils::Transform; use smithay::utils::Transform;
use crate::render_helpers::memory::MemoryBuffer;
use crate::render_helpers::primary_gpu_texture::PrimaryGpuTextureRenderElement;
use crate::render_helpers::renderer::NiriRenderer; use crate::render_helpers::renderer::NiriRenderer;
use crate::render_helpers::texture::{TextureBuffer, TextureRenderElement};
use crate::utils::output_size;
const TEXT: &str = "Are you sure you want to exit niri?\n\n\ const TEXT: &str = "Are you sure you want to exit niri?\n\n\
Press <span face='mono' bgcolor='#2C2C2C'> Enter </span> to confirm."; Press <span face='mono' bgcolor='#2C2C2C'> Enter </span> to confirm.";
@ -22,17 +23,17 @@ const BORDER: i32 = 8;
pub struct ExitConfirmDialog { pub struct ExitConfirmDialog {
is_open: bool, is_open: bool,
buffers: RefCell<HashMap<i32, Option<MemoryRenderBuffer>>>, buffers: RefCell<HashMap<NotNan<f64>, Option<MemoryBuffer>>>,
} }
pub type ExitConfirmDialogRenderElement<R> =
RelocateRenderElement<MemoryRenderBufferRenderElement<R>>;
impl ExitConfirmDialog { impl ExitConfirmDialog {
pub fn new() -> anyhow::Result<Self> { pub fn new() -> anyhow::Result<Self> {
Ok(Self { Ok(Self {
is_open: false, is_open: false,
buffers: RefCell::new(HashMap::from([(1, Some(render(1)?))])), buffers: RefCell::new(HashMap::from([(
NotNan::new(1.).unwrap(),
Some(render(1.)?),
)])),
}) })
} }
@ -62,52 +63,50 @@ impl ExitConfirmDialog {
&self, &self,
renderer: &mut R, renderer: &mut R,
output: &Output, output: &Output,
) -> Option<ExitConfirmDialogRenderElement<R>> { ) -> Option<PrimaryGpuTextureRenderElement> {
if !self.is_open { if !self.is_open {
return None; return None;
} }
let scale = output.current_scale().integer_scale(); let scale = output.current_scale().fractional_scale();
let output_size = output_size(output);
let mut buffers = self.buffers.borrow_mut(); let mut buffers = self.buffers.borrow_mut();
let fallback = buffers[&1].clone().unwrap(); let fallback = buffers[&NotNan::new(1.).unwrap()].clone().unwrap();
let buffer = buffers.entry(scale).or_insert_with(|| render(scale).ok()); let buffer = buffers
.entry(NotNan::new(scale).unwrap())
.or_insert_with(|| render(scale).ok());
let buffer = buffer.as_ref().unwrap_or(&fallback); let buffer = buffer.as_ref().unwrap_or(&fallback);
let elem = MemoryRenderBufferRenderElement::from_buffer( let size = buffer.logical_size();
renderer, let buffer = TextureBuffer::from_memory_buffer(renderer.as_gles_renderer(), buffer).ok()?;
(0., 0.),
let location = (output_size.to_f64().to_point() - size.to_point()).downscale(2.);
let mut location = location.to_physical_precise_round(scale).to_logical(scale);
location.x = f64::max(0., location.x);
location.y = f64::max(0., location.y);
let elem = TextureRenderElement::from_texture_buffer(
buffer, buffer,
None, location,
1.,
None, None,
None, None,
Kind::Unspecified, Kind::Unspecified,
) );
.ok()?; Some(PrimaryGpuTextureRenderElement(elem))
let output_transform = output.current_transform();
let output_mode = output.current_mode().unwrap();
let output_size = output_transform.transform_size(output_mode.size);
let buffer_size = elem
.geometry(output.current_scale().fractional_scale().into())
.size;
let x = (output_size.w / 2 - buffer_size.w / 2).max(0);
let y = (output_size.h / 2 - buffer_size.h / 2).max(0);
let elem = RelocateRenderElement::from_element(elem, (x, y), Relocate::Absolute);
Some(elem)
} }
} }
fn render(scale: i32) -> anyhow::Result<MemoryRenderBuffer> { fn render(scale: f64) -> anyhow::Result<MemoryBuffer> {
let _span = tracy_client::span!("exit_confirm_dialog::render"); let _span = tracy_client::span!("exit_confirm_dialog::render");
let padding = PADDING * scale; let apply_scale = |val: i32| (f64::from(val) * scale).round() as i32;
let padding = apply_scale(PADDING);
let mut font = FontDescription::from_string(FONT); let mut font = FontDescription::from_string(FONT);
font.set_absolute_size((font.size() * scale).into()); font.set_absolute_size(apply_scale(font.size()).into());
let surface = ImageSurface::create(cairo::Format::ARgb32, 0, 0)?; let surface = ImageSurface::create(cairo::Format::ARgb32, 0, 0)?;
let cr = cairo::Context::new(&surface)?; let cr = cairo::Context::new(&surface)?;
@ -120,10 +119,6 @@ fn render(scale: i32) -> anyhow::Result<MemoryRenderBuffer> {
width += padding * 2; width += padding * 2;
height += padding * 2; height += padding * 2;
// FIXME: fix bug in Smithay that rounds pixel sizes down to scale.
width = (width + scale - 1) / scale * scale;
height = (height + scale - 1) / scale * scale;
let surface = ImageSurface::create(cairo::Format::ARgb32, width, height)?; let surface = ImageSurface::create(cairo::Format::ARgb32, width, height)?;
let cr = cairo::Context::new(&surface)?; let cr = cairo::Context::new(&surface)?;
cr.set_source_rgb(0.1, 0.1, 0.1); cr.set_source_rgb(0.1, 0.1, 0.1);
@ -144,18 +139,18 @@ fn render(scale: i32) -> anyhow::Result<MemoryRenderBuffer> {
cr.line_to(0., height.into()); cr.line_to(0., height.into());
cr.line_to(0., 0.); cr.line_to(0., 0.);
cr.set_source_rgb(1., 0.3, 0.3); cr.set_source_rgb(1., 0.3, 0.3);
cr.set_line_width((BORDER * scale).into()); // Keep the border width even to avoid blurry edges.
cr.set_line_width((f64::from(BORDER) / 2. * scale).round() * 2.);
cr.stroke()?; cr.stroke()?;
drop(cr); drop(cr);
let data = surface.take_data().unwrap(); let data = surface.take_data().unwrap();
let buffer = MemoryRenderBuffer::from_slice( let buffer = MemoryBuffer::new(
&data, data.to_vec(),
Fourcc::Argb8888, Fourcc::Argb8888,
(width, height), (width, height),
scale, scale,
Transform::Normal, Transform::Normal,
None,
); );
Ok(buffer) Ok(buffer)