render: Scale contents according to zoom_level

This commit is contained in:
Victoria Brekenfeld 2025-01-23 15:45:00 +01:00 committed by Victoria Brekenfeld
parent 8e73fdebc6
commit 2e2943d99c
5 changed files with 105 additions and 26 deletions

View file

@ -256,6 +256,7 @@ pub fn draw_cursor<R>(
seat: &Seat<State>,
location: Point<f64, Logical>,
scale: Scale<f64>,
buffer_scale: f64,
time: Time<Monotonic>,
draw_default: bool,
) -> Vec<(CursorRenderElement<R>, Point<i32, BufferCoords>)>
@ -292,7 +293,7 @@ where
return Vec::new();
}
let integer_scale = scale.x.max(scale.y).ceil() as u32;
let integer_scale = (scale.x.max(scale.y) * buffer_scale).ceil() as u32;
let frame = state
.get_named_cursor(current_cursor)
.get_image(integer_scale, time.as_millis());

View file

@ -24,10 +24,12 @@ where
<R as Renderer>::TextureId: 'static,
CosmicMappedRenderElement<R>: RenderElement<R>,
{
Workspace(RelocateRenderElement<CropRenderElement<WorkspaceRenderElement<R>>>),
Cursor(RelocateRenderElement<CursorRenderElement<R>>),
Workspace(
RelocateRenderElement<CropRenderElement<RescaleRenderElement<WorkspaceRenderElement<R>>>>,
),
Cursor(RescaleRenderElement<RelocateRenderElement<CursorRenderElement<R>>>),
Dnd(WaylandSurfaceRenderElement<R>),
MoveGrab(CosmicMappedRenderElement<R>),
MoveGrab(RescaleRenderElement<CosmicMappedRenderElement<R>>),
AdditionalDamage(DamageElement),
Mirror(
CropRenderElement<
@ -266,13 +268,14 @@ where
}
}
impl<R> From<CropRenderElement<WorkspaceRenderElement<R>>> for CosmicElement<R>
impl<R> From<CropRenderElement<RescaleRenderElement<WorkspaceRenderElement<R>>>>
for CosmicElement<R>
where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
<R as Renderer>::TextureId: 'static,
CosmicMappedRenderElement<R>: RenderElement<R>,
{
fn from(elem: CropRenderElement<WorkspaceRenderElement<R>>) -> Self {
fn from(elem: CropRenderElement<RescaleRenderElement<WorkspaceRenderElement<R>>>) -> Self {
Self::Workspace(RelocateRenderElement::from_element(
elem,
(0, 0),
@ -281,17 +284,6 @@ where
}
}
impl<R> From<CosmicMappedRenderElement<R>> for CosmicElement<R>
where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
<R as Renderer>::TextureId: 'static,
CosmicMappedRenderElement<R>: RenderElement<R>,
{
fn from(elem: CosmicMappedRenderElement<R>) -> Self {
Self::MoveGrab(elem)
}
}
impl<R> From<DamageElement> for CosmicElement<R>
where
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,

View file

@ -42,7 +42,7 @@ use smithay::{
damage::{Error as RenderError, OutputDamageTracker, RenderOutputResult},
element::{
surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement},
utils::{CropRenderElement, Relocate, RelocateRenderElement},
utils::{CropRenderElement, Relocate, RelocateRenderElement, RescaleRenderElement},
AsRenderElements, Element, Id, Kind, RenderElement,
},
gles::{
@ -404,6 +404,7 @@ pub enum CursorMode {
pub fn cursor_elements<'a, 'frame, R>(
renderer: &mut R,
seats: impl Iterator<Item = &'a Seat<State>>,
zoom_level: Option<(Seat<State>, Point<f64, Global>, f64)>,
theme: &Theme,
now: Time<Monotonic>,
output: &Output,
@ -416,6 +417,9 @@ where
CosmicMappedRenderElement<R>: RenderElement<R>,
{
let scale = output.current_scale().fractional_scale();
let (focal_point, zoom_scale) = zoom_level
.map(|(_, p, s)| (p.to_local(&output), s))
.unwrap_or_else(|| ((0., 0.).into(), 1.));
let mut elements = Vec::new();
for seat in seats {
@ -432,15 +436,23 @@ where
&seat,
location,
scale.into(),
zoom_scale,
now,
mode != CursorMode::NotDefault,
)
.into_iter()
.map(|(elem, hotspot)| {
CosmicElement::Cursor(RelocateRenderElement::from_element(
elem,
Point::from((-hotspot.x, -hotspot.y)),
Relocate::Relative,
CosmicElement::Cursor(RescaleRenderElement::from_element(
RelocateRenderElement::from_element(
elem,
Point::from((-hotspot.x, -hotspot.y)),
Relocate::Relative,
),
focal_point
.as_logical()
.to_physical(output.current_scale().fractional_scale())
.to_i32_round(),
zoom_scale,
))
}),
);
@ -469,9 +481,18 @@ where
.lock()
.unwrap()
.as_ref()
.map(|state| state.render::<CosmicElement<R>, R>(renderer, output, theme))
.map(|state| state.render::<CosmicMappedRenderElement<R>, R>(renderer, output, theme))
{
elements.extend(grab_elements);
elements.extend(grab_elements.into_iter().map(|elem| {
CosmicElement::MoveGrab(RescaleRenderElement::from_element(
elem,
focal_point
.as_logical()
.to_physical(output.current_scale().fractional_scale())
.to_i32_round(),
zoom_scale,
))
}));
}
if let Some(grab_elements) = seat
@ -483,7 +504,16 @@ where
.as_ref()
.map(|state| state.render::<CosmicMappedRenderElement<R>, R>(renderer, output))
{
elements.extend(grab_elements.into_iter().map(Into::into));
elements.extend(grab_elements.into_iter().map(|elem| {
CosmicElement::MoveGrab(RescaleRenderElement::from_element(
elem,
focal_point
.as_logical()
.to_physical(output.current_scale().fractional_scale())
.to_i32_round(),
zoom_scale,
))
}));
}
}
@ -565,12 +595,14 @@ where
} else {
ElementFilter::All
};
let zoom_level = shell.read().unwrap().zoom_level();
#[allow(unused_mut)]
let workspace_elements = workspace_elements(
_gpu,
renderer,
shell,
zoom_level,
now,
output,
previous_workspace,
@ -593,6 +625,7 @@ pub fn workspace_elements<R>(
_gpu: Option<&DrmNode>,
renderer: &mut R,
shell: &Arc<RwLock<Shell>>,
zoom_level: Option<(Seat<State>, Point<f64, Global>, f64)>,
now: Time<Monotonic>,
output: &Output,
previous: Option<(WorkspaceHandle, usize, WorkspaceDelta)>,
@ -625,6 +658,7 @@ where
elements.extend(cursor_elements(
renderer,
seats.iter(),
zoom_level.clone(),
&theme,
now,
output,
@ -680,8 +714,23 @@ where
.size
.as_logical()
.to_physical_precise_round(scale);
let (focal_point, zoom_scale) = zoom_level
.map(|(_, p, s)| (p.to_local(&output), s))
.unwrap_or_else(|| ((0., 0.).into(), 1.));
let crop_to_output = |element: WorkspaceRenderElement<R>| {
CropRenderElement::from_element(element.into(), scale, Rectangle::from_size(output_size))
CropRenderElement::from_element(
RescaleRenderElement::from_element(
element.into(),
focal_point
.as_logical()
.to_physical(output.current_scale().fractional_scale())
.to_i32_round(),
zoom_scale,
),
scale,
Rectangle::from_size(output_size),
)
};
render_input_order(
@ -964,6 +1013,7 @@ where
} else {
ElementFilter::All
};
let zoom_level = shell.read().unwrap().zoom_level();
let result = render_workspace(
gpu,
@ -973,6 +1023,7 @@ where
age,
None,
shell,
zoom_level,
now,
output,
previous_workspace,
@ -1085,6 +1136,7 @@ pub fn render_workspace<'d, R, Target, OffTarget>(
age: usize,
additional_damage: Option<Vec<Rectangle<i32, Logical>>>,
shell: &Arc<RwLock<Shell>>,
zoom_level: Option<(Seat<State>, Point<f64, Global>, f64)>,
now: Time<Monotonic>,
output: &Output,
previous: Option<(WorkspaceHandle, usize, WorkspaceDelta)>,
@ -1111,6 +1163,7 @@ where
gpu,
renderer,
shell,
zoom_level,
now,
output,
previous,

View file

@ -245,6 +245,29 @@ pub struct PendingLayer {
pub output: Output,
}
pub struct ZoomState {
seat: Seat<State>,
level: f64,
focal_point: Point<f64, Global>,
previous: Option<(f64, Instant)>,
}
impl ZoomState {
pub fn level(&self) -> (Seat<State>, Point<f64, Global>, f64) {
if let Some((old, start)) = self.previous.as_ref() {
let percentage = Instant::now().duration_since(*start).as_millis() as f32
/ ANIMATION_DURATION.as_millis() as f32;
(
self.seat.clone(),
self.focal_point,
ease(EaseInOutCubic, *old, self.level, percentage),
)
} else {
(self.seat.clone(), self.focal_point, self.level)
}
}
}
#[derive(Debug)]
pub struct Shell {
pub workspaces: Workspaces,
@ -270,6 +293,7 @@ pub struct Shell {
Output,
)>,
resize_indicator: Option<ResizeIndicator>,
zoom_state: Option<ZoomState>,
tiling_exceptions: TilingExceptions,
#[cfg(feature = "debug")]
@ -1315,6 +1339,7 @@ impl Shell {
resize_mode: ResizeMode::None,
resize_state: None,
resize_indicator: None,
zoom_state: None,
tiling_exceptions,
#[cfg(feature = "debug")]
@ -1941,6 +1966,10 @@ impl Shell {
}
}
pub fn zoom_level(&self) -> Option<(Seat<State>, Point<f64, Global>, f64)> {
self.zoom_state.as_ref().map(|s| s.level())
}
fn refresh(
&mut self,
xdg_activation_state: &XdgActivationState,

View file

@ -281,6 +281,7 @@ pub fn render_workspace_to_buffer(
age,
additional_damage,
&common.shell,
None,
common.clock.now(),
&output,
None,
@ -311,6 +312,7 @@ pub fn render_workspace_to_buffer(
age,
additional_damage,
&common.shell,
None,
common.clock.now(),
&output,
None,
@ -525,6 +527,7 @@ pub fn render_window_to_buffer(
&seat,
location,
1.0.into(),
1.0,
common.clock.now(),
true,
)
@ -719,6 +722,7 @@ pub fn render_cursor_to_buffer(
&seat,
Point::from((0.0, 0.0)),
1.0.into(),
1.0,
common.clock.now(),
true,
)