From 2e2943d99caaac29e8ac1d672d45412def3a51de Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Thu, 23 Jan 2025 15:45:00 +0100 Subject: [PATCH] render: Scale contents according to zoom_level --- src/backend/render/cursor.rs | 3 +- src/backend/render/element.rs | 24 +++----- src/backend/render/mod.rs | 71 ++++++++++++++++++++--- src/shell/mod.rs | 29 +++++++++ src/wayland/handlers/screencopy/render.rs | 4 ++ 5 files changed, 105 insertions(+), 26 deletions(-) diff --git a/src/backend/render/cursor.rs b/src/backend/render/cursor.rs index ad5c6f99..ca673f15 100644 --- a/src/backend/render/cursor.rs +++ b/src/backend/render/cursor.rs @@ -256,6 +256,7 @@ pub fn draw_cursor( seat: &Seat, location: Point, scale: Scale, + buffer_scale: f64, time: Time, draw_default: bool, ) -> Vec<(CursorRenderElement, Point)> @@ -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()); diff --git a/src/backend/render/element.rs b/src/backend/render/element.rs index 87b86225..b2e5fcd1 100644 --- a/src/backend/render/element.rs +++ b/src/backend/render/element.rs @@ -24,10 +24,12 @@ where ::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { - Workspace(RelocateRenderElement>>), - Cursor(RelocateRenderElement>), + Workspace( + RelocateRenderElement>>>, + ), + Cursor(RescaleRenderElement>>), Dnd(WaylandSurfaceRenderElement), - MoveGrab(CosmicMappedRenderElement), + MoveGrab(RescaleRenderElement>), AdditionalDamage(DamageElement), Mirror( CropRenderElement< @@ -266,13 +268,14 @@ where } } -impl From>> for CosmicElement +impl From>>> + for CosmicElement where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { - fn from(elem: CropRenderElement>) -> Self { + fn from(elem: CropRenderElement>>) -> Self { Self::Workspace(RelocateRenderElement::from_element( elem, (0, 0), @@ -281,17 +284,6 @@ where } } -impl From> for CosmicElement -where - R: Renderer + ImportAll + ImportMem + AsGlowRenderer, - ::TextureId: 'static, - CosmicMappedRenderElement: RenderElement, -{ - fn from(elem: CosmicMappedRenderElement) -> Self { - Self::MoveGrab(elem) - } -} - impl From for CosmicElement where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index 3ffa53d7..9a9e0d30 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -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>, + zoom_level: Option<(Seat, Point, f64)>, theme: &Theme, now: Time, output: &Output, @@ -416,6 +417,9 @@ where CosmicMappedRenderElement: RenderElement, { 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::, R>(renderer, output, theme)) + .map(|state| state.render::, 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::, 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( _gpu: Option<&DrmNode>, renderer: &mut R, shell: &Arc>, + zoom_level: Option<(Seat, Point, f64)>, now: Time, 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| { - 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>>, shell: &Arc>, + zoom_level: Option<(Seat, Point, f64)>, now: Time, output: &Output, previous: Option<(WorkspaceHandle, usize, WorkspaceDelta)>, @@ -1111,6 +1163,7 @@ where gpu, renderer, shell, + zoom_level, now, output, previous, diff --git a/src/shell/mod.rs b/src/shell/mod.rs index e5a2c68f..71ec2f64 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -245,6 +245,29 @@ pub struct PendingLayer { pub output: Output, } +pub struct ZoomState { + seat: Seat, + level: f64, + focal_point: Point, + previous: Option<(f64, Instant)>, +} + +impl ZoomState { + pub fn level(&self) -> (Seat, Point, 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, + zoom_state: Option, 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, Point, f64)> { + self.zoom_state.as_ref().map(|s| s.level()) + } + fn refresh( &mut self, xdg_activation_state: &XdgActivationState, diff --git a/src/wayland/handlers/screencopy/render.rs b/src/wayland/handlers/screencopy/render.rs index 75d2be3b..3ee7628e 100644 --- a/src/wayland/handlers/screencopy/render.rs +++ b/src/wayland/handlers/screencopy/render.rs @@ -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, )