a11y/zoom: zoom level per output
This commit is contained in:
parent
babb96ddfa
commit
0ba0a0cdaa
11 changed files with 154 additions and 117 deletions
|
|
@ -79,7 +79,14 @@ pub fn init_backend_auto(
|
||||||
.accessibility_zoom
|
.accessibility_zoom
|
||||||
.start_on_login
|
.start_on_login
|
||||||
{
|
{
|
||||||
state.update_zoom(&initial_seat, 1.0, true);
|
state.common.shell.write().unwrap().trigger_zoom(
|
||||||
|
&initial_seat,
|
||||||
|
None,
|
||||||
|
1.0 + (state.common.config.cosmic_conf.accessibility_zoom.increment as f64 / 100.),
|
||||||
|
&state.common.config.cosmic_conf.accessibility_zoom,
|
||||||
|
true,
|
||||||
|
&state.common.event_loop_handle,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let desired_numlock = state
|
let desired_numlock = state
|
||||||
|
|
|
||||||
|
|
@ -433,7 +433,7 @@ where
|
||||||
.map(|state| {
|
.map(|state| {
|
||||||
(
|
(
|
||||||
state.animating_focal_point(Some(&output)).to_local(&output),
|
state.animating_focal_point(Some(&output)).to_local(&output),
|
||||||
state.animating_level(),
|
state.animating_level(&output),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| ((0., 0.).into(), 1.));
|
.unwrap_or_else(|| ((0., 0.).into(), 1.));
|
||||||
|
|
@ -741,7 +741,7 @@ where
|
||||||
.map(|state| {
|
.map(|state| {
|
||||||
(
|
(
|
||||||
state.animating_focal_point(Some(&output)).to_local(&output),
|
state.animating_focal_point(Some(&output)).to_local(&output),
|
||||||
state.animating_level(),
|
state.animating_level(&output),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| ((0., 0.).into(), 1.));
|
.unwrap_or_else(|| ((0., 0.).into(), 1.));
|
||||||
|
|
|
||||||
|
|
@ -1027,10 +1027,11 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_zoom(&mut self, seat: &Seat<State>, change: f64, animate: bool) {
|
pub fn update_zoom(&mut self, seat: &Seat<State>, change: f64, animate: bool) {
|
||||||
|
let output = seat.active_output();
|
||||||
let mut shell = self.common.shell.write().unwrap();
|
let mut shell = self.common.shell.write().unwrap();
|
||||||
let (zoom_seat, current_level) = shell
|
let (zoom_seat, current_level) = shell
|
||||||
.zoom_state()
|
.zoom_state()
|
||||||
.map(|state| (state.current_seat(), state.current_level()))
|
.map(|state| (state.current_seat(), state.current_level(&output)))
|
||||||
.unwrap_or_else(|| (seat.clone(), 1.0));
|
.unwrap_or_else(|| (seat.clone(), 1.0));
|
||||||
|
|
||||||
if current_level == 1. && change <= 0. {
|
if current_level == 1. && change <= 0. {
|
||||||
|
|
@ -1041,6 +1042,7 @@ impl State {
|
||||||
let new_level = (current_level + change).max(1.0);
|
let new_level = (current_level + change).max(1.0);
|
||||||
shell.trigger_zoom(
|
shell.trigger_zoom(
|
||||||
&seat,
|
&seat,
|
||||||
|
Some(&output),
|
||||||
new_level,
|
new_level,
|
||||||
&self.common.config.cosmic_conf.accessibility_zoom,
|
&self.common.config.cosmic_conf.accessibility_zoom,
|
||||||
animate,
|
animate,
|
||||||
|
|
|
||||||
|
|
@ -2247,7 +2247,7 @@ where
|
||||||
B::Device: 'static,
|
B::Device: 'static,
|
||||||
{
|
{
|
||||||
let geometry = zoom_state
|
let geometry = zoom_state
|
||||||
.and_then(|state| output.zoomed_geometry(state.current_level()))
|
.and_then(|_| output.zoomed_geometry())
|
||||||
.unwrap_or_else(|| output.geometry());
|
.unwrap_or_else(|| output.geometry());
|
||||||
let transform = output.current_transform();
|
let transform = output.current_transform();
|
||||||
let size = transform
|
let size = transform
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ fn render_input_order_internal<R: 'static>(
|
||||||
if shell
|
if shell
|
||||||
.zoom_state
|
.zoom_state
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|state| state.show_overlay && state.current_level() != 1.0)
|
.is_some_and(|state| state.show_overlay && state.current_level(output) != 1.0)
|
||||||
{
|
{
|
||||||
callback(Stage::ZoomUI)?;
|
callback(Stage::ZoomUI)?;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -522,11 +522,11 @@ impl PointerGrab<State> for MenuGrab {
|
||||||
let mut guard = self.elements.lock().unwrap();
|
let mut guard = self.elements.lock().unwrap();
|
||||||
let elements = &mut *guard;
|
let elements = &mut *guard;
|
||||||
let event_location = if let Some(output) = self.screen_space_relative.as_ref() {
|
let event_location = if let Some(output) = self.screen_space_relative.as_ref() {
|
||||||
if let Some(zoom_state) = state.common.shell.read().unwrap().zoom_state() {
|
if state.common.shell.read().unwrap().zoom_state().is_some() {
|
||||||
event
|
event
|
||||||
.location
|
.location
|
||||||
.as_global()
|
.as_global()
|
||||||
.to_zoomed(output, zoom_state.level)
|
.to_zoomed(output)
|
||||||
.to_global(output)
|
.to_global(output)
|
||||||
.as_logical()
|
.as_logical()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -726,11 +726,11 @@ impl TouchGrab<State> for MenuGrab {
|
||||||
let mut guard = self.elements.lock().unwrap();
|
let mut guard = self.elements.lock().unwrap();
|
||||||
let elements = &mut *guard;
|
let elements = &mut *guard;
|
||||||
let event_location = if let Some(output) = self.screen_space_relative.as_ref() {
|
let event_location = if let Some(output) = self.screen_space_relative.as_ref() {
|
||||||
if let Some(zoom_state) = data.common.shell.read().unwrap().zoom_state() {
|
if data.common.shell.read().unwrap().zoom_state().is_some() {
|
||||||
event
|
event
|
||||||
.location
|
.location
|
||||||
.as_global()
|
.as_global()
|
||||||
.to_zoomed(output, zoom_state.level)
|
.to_zoomed(output)
|
||||||
.to_global(output)
|
.to_global(output)
|
||||||
.as_logical()
|
.as_logical()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
118
src/shell/mod.rs
118
src/shell/mod.rs
|
|
@ -1202,7 +1202,7 @@ impl Common {
|
||||||
Mutex::new(OutputZoomState::new(
|
Mutex::new(OutputZoomState::new(
|
||||||
&state.seat,
|
&state.seat,
|
||||||
output,
|
output,
|
||||||
state.level,
|
1.0,
|
||||||
state.increment,
|
state.increment,
|
||||||
state.movement,
|
state.movement,
|
||||||
self.event_loop_handle.clone(),
|
self.event_loop_handle.clone(),
|
||||||
|
|
@ -1253,11 +1253,9 @@ impl Common {
|
||||||
|
|
||||||
for output in shell_ref.workspaces.sets.keys() {
|
for output in shell_ref.workspaces.sets.keys() {
|
||||||
let output_state = output.user_data().get::<Mutex<OutputZoomState>>().unwrap();
|
let output_state = output.user_data().get::<Mutex<OutputZoomState>>().unwrap();
|
||||||
output_state.lock().unwrap().update(
|
let mut output_state_ref = output_state.lock().unwrap();
|
||||||
zoom_state.level,
|
let level = output_state_ref.level;
|
||||||
zoom_state.movement,
|
output_state_ref.update(level, false, zoom_state.movement, zoom_state.increment);
|
||||||
zoom_state.increment,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1861,13 +1859,12 @@ impl Shell {
|
||||||
.workspaces
|
.workspaces
|
||||||
.spaces()
|
.spaces()
|
||||||
.any(|workspace| workspace.animations_going())
|
.any(|workspace| workspace.animations_going())
|
||||||
|| self.zoom_state.as_ref().is_some_and(|state| {
|
|| self.zoom_state.as_ref().is_some_and(|_| {
|
||||||
state.previous_level.is_some()
|
self.outputs().any(|o| {
|
||||||
|| self.outputs().any(|o| {
|
o.user_data()
|
||||||
o.user_data()
|
.get::<Mutex<OutputZoomState>>()
|
||||||
.get::<Mutex<OutputZoomState>>()
|
.is_some_and(|state| state.lock().unwrap().is_animating())
|
||||||
.is_some_and(|state| state.lock().unwrap().is_animating())
|
})
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2005,6 +2002,7 @@ impl Shell {
|
||||||
pub fn trigger_zoom(
|
pub fn trigger_zoom(
|
||||||
&mut self,
|
&mut self,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
|
output: Option<&Output>,
|
||||||
level: f64,
|
level: f64,
|
||||||
zoom_config: &ZoomConfig,
|
zoom_config: &ZoomConfig,
|
||||||
animate: bool,
|
animate: bool,
|
||||||
|
|
@ -2014,51 +2012,53 @@ impl Shell {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let previous_level = if let Some(old_state) = self.zoom_state.as_ref() {
|
let outputs = output.map(|o| vec![o]).unwrap_or(self.outputs().collect());
|
||||||
if &old_state.seat != seat {
|
if self.zoom_state.is_none() {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for output in self.outputs() {
|
for output in self.outputs() {
|
||||||
let output_state = output.user_data().get::<Mutex<OutputZoomState>>().unwrap();
|
output.user_data().insert_if_missing_threadsafe(|| {
|
||||||
output_state.lock().unwrap().update(
|
|
||||||
level,
|
|
||||||
zoom_config.view_moves,
|
|
||||||
zoom_config.increment,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
old_state.animating_level()
|
|
||||||
} else {
|
|
||||||
for output in self.outputs() {
|
|
||||||
let output_state = output.user_data().get_or_insert_threadsafe(|| {
|
|
||||||
Mutex::new(OutputZoomState::new(
|
Mutex::new(OutputZoomState::new(
|
||||||
seat,
|
seat,
|
||||||
output,
|
output,
|
||||||
level,
|
1.0,
|
||||||
zoom_config.increment,
|
zoom_config.increment,
|
||||||
zoom_config.view_moves,
|
zoom_config.view_moves,
|
||||||
loop_handle.clone(),
|
loop_handle.clone(),
|
||||||
self.theme.clone(),
|
self.theme.clone(),
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
*output_state.lock().unwrap() = OutputZoomState::new(
|
|
||||||
seat,
|
|
||||||
output,
|
|
||||||
level,
|
|
||||||
zoom_config.increment,
|
|
||||||
zoom_config.view_moves,
|
|
||||||
loop_handle.clone(),
|
|
||||||
self.theme.clone(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
1.
|
let mut toggled = self.zoom_state.is_none();
|
||||||
};
|
if let Some(old_state) = self.zoom_state.as_ref() {
|
||||||
|
if &old_state.seat != seat {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for output in &outputs {
|
||||||
|
let output_state = output.user_data().get::<Mutex<OutputZoomState>>().unwrap();
|
||||||
|
output_state.lock().unwrap().update(
|
||||||
|
level,
|
||||||
|
animate,
|
||||||
|
zoom_config.view_moves,
|
||||||
|
zoom_config.increment,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let all_outputs_off = self.outputs().all(|o| {
|
||||||
|
o.user_data()
|
||||||
|
.get::<Mutex<OutputZoomState>>()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.current_level()
|
||||||
|
== 1.0
|
||||||
|
});
|
||||||
|
toggled = toggled || all_outputs_off;
|
||||||
|
|
||||||
let toggled = previous_level != level && (previous_level == 1.0 || level == 1.0);
|
|
||||||
if toggled {
|
if toggled {
|
||||||
let value = previous_level == 1.0;
|
let value = !all_outputs_off;
|
||||||
let _ = loop_handle.insert_idle(move |state| {
|
let _ = loop_handle.insert_idle(move |state| {
|
||||||
state.common.a11y_state.set_screen_magnifier(value);
|
state.common.a11y_state.set_screen_magnifier(value);
|
||||||
});
|
});
|
||||||
|
|
@ -2067,10 +2067,8 @@ impl Shell {
|
||||||
self.zoom_state = Some(ZoomState {
|
self.zoom_state = Some(ZoomState {
|
||||||
seat: seat.clone(),
|
seat: seat.clone(),
|
||||||
show_overlay: zoom_config.show_overlay,
|
show_overlay: zoom_config.show_overlay,
|
||||||
level,
|
|
||||||
increment: zoom_config.increment,
|
increment: zoom_config.increment,
|
||||||
movement: zoom_config.view_moves,
|
movement: zoom_config.view_moves,
|
||||||
previous_level: animate.then_some((previous_level, Instant::now())),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2135,31 +2133,21 @@ impl Shell {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(zoom_state) = self.zoom_state.as_mut() {
|
if self.zoom_state.is_some() {
|
||||||
if zoom_state
|
let mut all_outputs_off = true;
|
||||||
.previous_level
|
for output in self.outputs() {
|
||||||
.as_ref()
|
all_outputs_off = all_outputs_off
|
||||||
.is_some_and(|(_, start)| {
|
&& output
|
||||||
Instant::now().duration_since(*start) > ANIMATION_DURATION
|
|
||||||
})
|
|
||||||
{
|
|
||||||
zoom_state.previous_level.take();
|
|
||||||
}
|
|
||||||
|
|
||||||
if zoom_state.level == 1. && zoom_state.previous_level.is_none() {
|
|
||||||
self.zoom_state.take();
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.zoom_state.is_some() {
|
|
||||||
for output in self.outputs() {
|
|
||||||
output
|
|
||||||
.user_data()
|
.user_data()
|
||||||
.get::<Mutex<OutputZoomState>>()
|
.get::<Mutex<OutputZoomState>>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.refresh();
|
.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if all_outputs_off {
|
||||||
|
self.zoom_state.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,14 +52,14 @@ use super::{
|
||||||
pub struct ZoomState {
|
pub struct ZoomState {
|
||||||
pub(super) seat: Seat<State>,
|
pub(super) seat: Seat<State>,
|
||||||
pub(super) show_overlay: bool,
|
pub(super) show_overlay: bool,
|
||||||
pub(super) level: f64,
|
|
||||||
pub(super) increment: u32,
|
pub(super) increment: u32,
|
||||||
pub(super) movement: ZoomMovement,
|
pub(super) movement: ZoomMovement,
|
||||||
pub(super) previous_level: Option<(f64, Instant)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct OutputZoomState {
|
pub struct OutputZoomState {
|
||||||
|
pub(super) level: f64,
|
||||||
|
pub(super) previous_level: Option<(f64, Instant)>,
|
||||||
focal_point: Point<f64, Local>,
|
focal_point: Point<f64, Local>,
|
||||||
previous_point: Option<(Point<f64, Local>, Instant)>,
|
previous_point: Option<(Point<f64, Local>, Instant)>,
|
||||||
element: ZoomElement,
|
element: ZoomElement,
|
||||||
|
|
@ -118,6 +118,8 @@ impl OutputZoomState {
|
||||||
element.set_additional_scale(level.min(4.));
|
element.set_additional_scale(level.min(4.));
|
||||||
|
|
||||||
OutputZoomState {
|
OutputZoomState {
|
||||||
|
level,
|
||||||
|
previous_level: None,
|
||||||
focal_point,
|
focal_point,
|
||||||
previous_point: None,
|
previous_point: None,
|
||||||
element,
|
element,
|
||||||
|
|
@ -150,15 +152,40 @@ impl OutputZoomState {
|
||||||
self.focal_point
|
self.focal_point
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn current_level(&self) -> f64 {
|
||||||
|
self.level
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn animating_level(&self) -> f64 {
|
||||||
|
if let Some((old_level, start)) = self.previous_level.as_ref() {
|
||||||
|
let percentage = Instant::now().duration_since(*start).as_millis() as f32
|
||||||
|
/ ANIMATION_DURATION.as_millis() as f32;
|
||||||
|
|
||||||
|
ease(EaseInOutCubic, *old_level, self.level, percentage)
|
||||||
|
} else {
|
||||||
|
self.level
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_animating(&self) -> bool {
|
pub fn is_animating(&self) -> bool {
|
||||||
self.previous_point.is_some()
|
self.previous_point.is_some() || self.previous_level.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refresh(&self) {
|
pub fn refresh(&mut self) -> bool {
|
||||||
self.element.refresh()
|
if self
|
||||||
|
.previous_level
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|(_, start)| Instant::now().duration_since(*start) > ANIMATION_DURATION)
|
||||||
|
{
|
||||||
|
self.previous_level.take();
|
||||||
|
}
|
||||||
|
self.element.refresh();
|
||||||
|
self.level == 1. && self.previous_level.is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&self, level: f64, movement: ZoomMovement, increment: u32) {
|
pub fn update(&mut self, level: f64, animate: bool, movement: ZoomMovement, increment: u32) {
|
||||||
|
self.previous_level = animate.then_some((self.animating_level(), Instant::now()));
|
||||||
|
self.level = level;
|
||||||
self.element.set_additional_scale(level.min(4.));
|
self.element.set_additional_scale(level.min(4.));
|
||||||
self.element.queue_message(ZoomMessage::Update {
|
self.element.queue_message(ZoomMessage::Update {
|
||||||
level,
|
level,
|
||||||
|
|
@ -189,25 +216,20 @@ impl OutputZoomState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ZoomState {
|
impl ZoomState {
|
||||||
pub fn current_level(&self) -> f64 {
|
|
||||||
self.level
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn animating_level(&self) -> f64 {
|
|
||||||
if let Some((old_level, start)) = self.previous_level.as_ref() {
|
|
||||||
let percentage = Instant::now().duration_since(*start).as_millis() as f32
|
|
||||||
/ ANIMATION_DURATION.as_millis() as f32;
|
|
||||||
|
|
||||||
ease(EaseInOutCubic, *old_level, self.level, percentage)
|
|
||||||
} else {
|
|
||||||
self.level
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn current_seat(&self) -> Seat<State> {
|
pub fn current_seat(&self) -> Seat<State> {
|
||||||
self.seat.clone()
|
self.seat.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn current_level(&self, output: &Output) -> f64 {
|
||||||
|
let output_state = output.user_data().get::<Mutex<OutputZoomState>>().unwrap();
|
||||||
|
output_state.lock().unwrap().current_level()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn animating_level(&self, output: &Output) -> f64 {
|
||||||
|
let output_state = output.user_data().get::<Mutex<OutputZoomState>>().unwrap();
|
||||||
|
output_state.lock().unwrap().animating_level()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn animating_focal_point(&self, output: Option<&Output>) -> Point<f64, Global> {
|
pub fn animating_focal_point(&self, output: Option<&Output>) -> Point<f64, Global> {
|
||||||
let active_output = self.seat.active_output();
|
let active_output = self.seat.active_output();
|
||||||
let output = output.unwrap_or(&active_output);
|
let output = output.unwrap_or(&active_output);
|
||||||
|
|
@ -242,7 +264,7 @@ impl ZoomState {
|
||||||
let cursor_position = cursor_position.to_i32_round();
|
let cursor_position = cursor_position.to_i32_round();
|
||||||
let original_position = original_position.to_i32_round();
|
let original_position = original_position.to_i32_round();
|
||||||
let output_geometry = output.geometry();
|
let output_geometry = output.geometry();
|
||||||
let mut zoomed_output_geometry = output.zoomed_geometry(self.level).unwrap();
|
let mut zoomed_output_geometry = output.zoomed_geometry().unwrap();
|
||||||
|
|
||||||
let output_state = output.user_data().get::<Mutex<OutputZoomState>>().unwrap();
|
let output_state = output.user_data().get::<Mutex<OutputZoomState>>().unwrap();
|
||||||
let mut output_state_ref = output_state.lock().unwrap();
|
let mut output_state_ref = output_state.lock().unwrap();
|
||||||
|
|
@ -285,7 +307,7 @@ impl ZoomState {
|
||||||
let mut diff = output_state_ref.focal_point.to_global(&output)
|
let mut diff = output_state_ref.focal_point.to_global(&output)
|
||||||
+ (cursor_position.to_global(&output) - original_position)
|
+ (cursor_position.to_global(&output) - original_position)
|
||||||
.to_f64()
|
.to_f64()
|
||||||
.upscale(self.level);
|
.upscale(output_state_ref.level);
|
||||||
diff.x = diff.x.clamp(
|
diff.x = diff.x.clamp(
|
||||||
output_geometry.loc.x as f64,
|
output_geometry.loc.x as f64,
|
||||||
((output_geometry.loc.x + output_geometry.size.w) as f64).next_lower(), // FIXME: Replace with f64::next_down when stable
|
((output_geometry.loc.x + output_geometry.size.w) as f64).next_lower(), // FIXME: Replace with f64::next_down when stable
|
||||||
|
|
@ -333,9 +355,9 @@ impl ZoomState {
|
||||||
pos: Point<f64, Global>,
|
pos: Point<f64, Global>,
|
||||||
) -> Option<(PointerFocusTarget, Point<f64, Global>)> {
|
) -> Option<(PointerFocusTarget, Point<f64, Global>)> {
|
||||||
let output_geometry = output.geometry();
|
let output_geometry = output.geometry();
|
||||||
let zoomed_output_geometry = output.zoomed_geometry(self.level).unwrap().to_f64();
|
let zoomed_output_geometry = output.zoomed_geometry().unwrap().to_f64();
|
||||||
|
let local_pos = global_pos_to_screen_space(pos, output);
|
||||||
|
|
||||||
let local_pos = global_pos_to_screen_space(pos, output, self.level);
|
|
||||||
let output_state = output.user_data().get::<Mutex<OutputZoomState>>().unwrap();
|
let output_state = output.user_data().get::<Mutex<OutputZoomState>>().unwrap();
|
||||||
let output_state_ref = output_state.lock().unwrap();
|
let output_state_ref = output_state.lock().unwrap();
|
||||||
|
|
||||||
|
|
@ -351,7 +373,7 @@ impl ZoomState {
|
||||||
PointerFocusTarget::ZoomUI(output_state_ref.element.clone().into()),
|
PointerFocusTarget::ZoomUI(output_state_ref.element.clone().into()),
|
||||||
{
|
{
|
||||||
// and vise-versa from screen-space to zoom-space...
|
// and vise-versa from screen-space to zoom-space...
|
||||||
let scaled_loc = location.downscale(self.level);
|
let scaled_loc = location.downscale(output_state_ref.level);
|
||||||
let global_loc = Point::<f64, Global>::from((scaled_loc.x, scaled_loc.y))
|
let global_loc = Point::<f64, Global>::from((scaled_loc.x, scaled_loc.y))
|
||||||
+ zoomed_output_geometry.loc;
|
+ zoomed_output_geometry.loc;
|
||||||
|
|
||||||
|
|
@ -359,7 +381,7 @@ impl ZoomState {
|
||||||
// the relative position for us... Which will be wrong given the cursor movement will
|
// the relative position for us... Which will be wrong given the cursor movement will
|
||||||
// be scaled, while this element isn't, as it exists in screen-space and not workspace-space.
|
// be scaled, while this element isn't, as it exists in screen-space and not workspace-space.
|
||||||
// So we shift the location relatively to make up for the scaled movement...
|
// So we shift the location relatively to make up for the scaled movement...
|
||||||
let diff = (pos - global_loc).upscale(self.level - 1.);
|
let diff = (pos - global_loc).upscale(output_state_ref.level - 1.);
|
||||||
|
|
||||||
global_loc - diff
|
global_loc - diff
|
||||||
},
|
},
|
||||||
|
|
@ -383,10 +405,16 @@ impl ZoomState {
|
||||||
fn global_pos_to_screen_space(
|
fn global_pos_to_screen_space(
|
||||||
pos: impl Into<Point<f64, Global>>,
|
pos: impl Into<Point<f64, Global>>,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
level: f64,
|
|
||||||
) -> Point<f64, Local> {
|
) -> Point<f64, Local> {
|
||||||
let pos = pos.into();
|
let pos = pos.into();
|
||||||
let zoomed_output_geometry = output.zoomed_geometry(level).unwrap().to_f64();
|
let zoomed_output_geometry = output.zoomed_geometry().unwrap().to_f64();
|
||||||
|
let level = output
|
||||||
|
.user_data()
|
||||||
|
.get::<Mutex<OutputZoomState>>()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.current_level();
|
||||||
|
|
||||||
// lets try to get the global cursor position into screen space
|
// lets try to get the global cursor position into screen space
|
||||||
let relative_to_zoom_geo = Point::<f64, Local>::from((
|
let relative_to_zoom_geo = Point::<f64, Local>::from((
|
||||||
|
|
@ -551,11 +579,10 @@ impl Program for ZoomProgram {
|
||||||
let shell = state.common.shell.read().unwrap();
|
let shell = state.common.shell.read().unwrap();
|
||||||
let output = seat.active_output();
|
let output = seat.active_output();
|
||||||
|
|
||||||
if let Some(zoom_state) = shell.zoom_state() {
|
if shell.zoom_state().is_some() {
|
||||||
let location = global_pos_to_screen_space(
|
let location = global_pos_to_screen_space(
|
||||||
start_data.location().as_global(),
|
start_data.location().as_global(),
|
||||||
&output,
|
&output,
|
||||||
zoom_state.current_level(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let output_geometry = output.geometry();
|
let output_geometry = output.geometry();
|
||||||
|
|
@ -573,6 +600,7 @@ impl Program for ZoomProgram {
|
||||||
location.x,
|
location.x,
|
||||||
elem_location.y + elem_size.h / 2.,
|
elem_location.y + elem_size.h / 2.,
|
||||||
));
|
));
|
||||||
|
let level = output_state_ref.level;
|
||||||
std::mem::drop(output_state_ref);
|
std::mem::drop(output_state_ref);
|
||||||
|
|
||||||
let grab = MenuGrab::new(
|
let grab = MenuGrab::new(
|
||||||
|
|
@ -684,7 +712,7 @@ impl Program for ZoomProgram {
|
||||||
(elem_size.h / 2.).round() as u32,
|
(elem_size.h / 2.).round() as u32,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
Some(zoom_state.level.min(4.)),
|
Some(level.min(4.)),
|
||||||
state.common.event_loop_handle.clone(),
|
state.common.event_loop_handle.clone(),
|
||||||
state.common.theme.clone(),
|
state.common.theme.clone(),
|
||||||
);
|
);
|
||||||
|
|
@ -715,11 +743,10 @@ impl Program for ZoomProgram {
|
||||||
let shell = state.common.shell.read().unwrap();
|
let shell = state.common.shell.read().unwrap();
|
||||||
let output = seat.active_output();
|
let output = seat.active_output();
|
||||||
|
|
||||||
if let Some(zoom_state) = shell.zoom_state() {
|
if shell.zoom_state().is_some() {
|
||||||
let location = global_pos_to_screen_space(
|
let location = global_pos_to_screen_space(
|
||||||
start_data.location().as_global(),
|
start_data.location().as_global(),
|
||||||
&output,
|
&output,
|
||||||
zoom_state.current_level(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let output_geometry = output.geometry();
|
let output_geometry = output.geometry();
|
||||||
|
|
@ -737,6 +764,7 @@ impl Program for ZoomProgram {
|
||||||
location.x,
|
location.x,
|
||||||
elem_location.y + (elem_size.h / 2.),
|
elem_location.y + (elem_size.h / 2.),
|
||||||
));
|
));
|
||||||
|
let level = output_state_ref.level;
|
||||||
std::mem::drop(output_state_ref);
|
std::mem::drop(output_state_ref);
|
||||||
|
|
||||||
let grab = MenuGrab::new(
|
let grab = MenuGrab::new(
|
||||||
|
|
@ -758,7 +786,7 @@ impl Program for ZoomProgram {
|
||||||
}),
|
}),
|
||||||
position.to_global(&output).to_i32_round(),
|
position.to_global(&output).to_i32_round(),
|
||||||
MenuAlignment::PREFER_CENTERED,
|
MenuAlignment::PREFER_CENTERED,
|
||||||
Some(zoom_state.level.min(4.)),
|
Some(level.min(4.)),
|
||||||
state.common.event_loop_handle.clone(),
|
state.common.event_loop_handle.clone(),
|
||||||
state.common.theme.clone(),
|
state.common.theme.clone(),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
output::Output,
|
output::Output,
|
||||||
utils::{Coordinate, Logical, Point, Rectangle, Size},
|
utils::{Coordinate, Logical, Point, Rectangle, Size},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::shell::zoom::OutputZoomState;
|
||||||
|
|
||||||
use super::prelude::OutputExt;
|
use super::prelude::OutputExt;
|
||||||
|
|
||||||
/// Marker type for coordinates in global space
|
/// Marker type for coordinates in global space
|
||||||
|
|
@ -20,7 +24,7 @@ pub trait PointExt<C: Coordinate> {
|
||||||
|
|
||||||
pub trait PointGlobalExt<C: Coordinate> {
|
pub trait PointGlobalExt<C: Coordinate> {
|
||||||
fn to_local(self, output: &Output) -> Point<C, Local>;
|
fn to_local(self, output: &Output) -> Point<C, Local>;
|
||||||
fn to_zoomed(self, output: &Output, level: f64) -> Point<C, Local>;
|
fn to_zoomed(self, output: &Output) -> Point<C, Local>;
|
||||||
fn as_logical(self) -> Point<C, Logical>;
|
fn as_logical(self) -> Point<C, Logical>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,8 +70,15 @@ impl<C: Coordinate> PointGlobalExt<C> for Point<C, Global> {
|
||||||
(C::from_f64(point.x), C::from_f64(point.y)).into()
|
(C::from_f64(point.x), C::from_f64(point.y)).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_zoomed(self, output: &Output, level: f64) -> Point<C, Local> {
|
fn to_zoomed(self, output: &Output) -> Point<C, Local> {
|
||||||
let zoomed_output_geometry = output.zoomed_geometry(level).unwrap();
|
let zoomed_output_geometry = output.zoomed_geometry().unwrap();
|
||||||
|
let level = output
|
||||||
|
.user_data()
|
||||||
|
.get::<Mutex<OutputZoomState>>()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.current_level();
|
||||||
let point = (self.to_f64() - zoomed_output_geometry.loc.to_f64())
|
let point = (self.to_f64() - zoomed_output_geometry.loc.to_f64())
|
||||||
.upscale(level)
|
.upscale(level)
|
||||||
.as_logical();
|
.as_logical();
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ use std::{
|
||||||
|
|
||||||
pub trait OutputExt {
|
pub trait OutputExt {
|
||||||
fn geometry(&self) -> Rectangle<i32, Global>;
|
fn geometry(&self) -> Rectangle<i32, Global>;
|
||||||
fn zoomed_geometry(&self, level: f64) -> Option<Rectangle<i32, Global>>;
|
fn zoomed_geometry(&self) -> Option<Rectangle<i32, Global>>;
|
||||||
|
|
||||||
fn adaptive_sync(&self) -> AdaptiveSync;
|
fn adaptive_sync(&self) -> AdaptiveSync;
|
||||||
fn set_adaptive_sync(&self, vrr: AdaptiveSync);
|
fn set_adaptive_sync(&self, vrr: AdaptiveSync);
|
||||||
|
|
@ -57,7 +57,7 @@ impl OutputExt for Output {
|
||||||
.as_global()
|
.as_global()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zoomed_geometry(&self, level: f64) -> Option<Rectangle<i32, Global>> {
|
fn zoomed_geometry(&self) -> Option<Rectangle<i32, Global>> {
|
||||||
let output_geometry = self.geometry();
|
let output_geometry = self.geometry();
|
||||||
|
|
||||||
let output_state = self.user_data().get::<Mutex<OutputZoomState>>()?;
|
let output_state = self.user_data().get::<Mutex<OutputZoomState>>()?;
|
||||||
|
|
@ -66,7 +66,7 @@ impl OutputExt for Output {
|
||||||
let focal_point = output_state_ref.current_focal_point().to_global(self);
|
let focal_point = output_state_ref.current_focal_point().to_global(self);
|
||||||
let mut zoomed_output_geo = output_geometry.to_f64();
|
let mut zoomed_output_geo = output_geometry.to_f64();
|
||||||
zoomed_output_geo.loc -= focal_point;
|
zoomed_output_geo.loc -= focal_point;
|
||||||
zoomed_output_geo = zoomed_output_geo.downscale(level);
|
zoomed_output_geo = zoomed_output_geo.downscale(output_state_ref.current_level());
|
||||||
zoomed_output_geo.loc += focal_point;
|
zoomed_output_geo.loc += focal_point;
|
||||||
|
|
||||||
Some(zoomed_output_geo.to_i32_round())
|
Some(zoomed_output_geo.to_i32_round())
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ impl A11yHandler for State {
|
||||||
|
|
||||||
if shell
|
if shell
|
||||||
.zoom_state()
|
.zoom_state()
|
||||||
.is_some_and(|state| state.current_level() != 1.0)
|
.is_some_and(|state| shell.outputs().any(|o| state.current_level(o) != 1.0))
|
||||||
!= enabled
|
!= enabled
|
||||||
{
|
{
|
||||||
let seat = shell.seats.last_active().clone();
|
let seat = shell.seats.last_active().clone();
|
||||||
|
|
@ -29,6 +29,7 @@ impl A11yHandler for State {
|
||||||
|
|
||||||
shell.trigger_zoom(
|
shell.trigger_zoom(
|
||||||
&seat,
|
&seat,
|
||||||
|
None,
|
||||||
level,
|
level,
|
||||||
zoom_config,
|
zoom_config,
|
||||||
true,
|
true,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue