gestures: Cycle through workspaces
This commit is contained in:
parent
1f2863fa18
commit
8624928052
4 changed files with 123 additions and 53 deletions
|
|
@ -1108,18 +1108,21 @@ fn to_next_workspace(
|
||||||
workspace_state: &mut WorkspaceUpdateGuard<'_, State>,
|
workspace_state: &mut WorkspaceUpdateGuard<'_, State>,
|
||||||
) -> Result<Point<i32, Global>, InvalidWorkspaceIndex> {
|
) -> Result<Point<i32, Global>, InvalidWorkspaceIndex> {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
let workspace = shell
|
let active = shell.workspaces.active_num(¤t_output).1;
|
||||||
.workspaces
|
let mut workspace = active.checked_add(1).ok_or(InvalidWorkspaceIndex)?;
|
||||||
.active_num(¤t_output)
|
|
||||||
.1
|
if workspace >= shell.workspaces.len(¤t_output) {
|
||||||
.checked_add(1)
|
workspace = 0;
|
||||||
.ok_or(InvalidWorkspaceIndex)?;
|
}
|
||||||
|
if workspace == active {
|
||||||
|
return Err(InvalidWorkspaceIndex);
|
||||||
|
}
|
||||||
|
|
||||||
shell.activate(
|
shell.activate(
|
||||||
¤t_output,
|
¤t_output,
|
||||||
workspace,
|
workspace,
|
||||||
if gesture {
|
if gesture {
|
||||||
WorkspaceDelta::new_gesture()
|
WorkspaceDelta::new_gesture(true)
|
||||||
} else {
|
} else {
|
||||||
WorkspaceDelta::new_shortcut()
|
WorkspaceDelta::new_shortcut()
|
||||||
},
|
},
|
||||||
|
|
@ -1134,18 +1137,24 @@ fn to_previous_workspace(
|
||||||
workspace_state: &mut WorkspaceUpdateGuard<'_, State>,
|
workspace_state: &mut WorkspaceUpdateGuard<'_, State>,
|
||||||
) -> Result<Point<i32, Global>, InvalidWorkspaceIndex> {
|
) -> Result<Point<i32, Global>, InvalidWorkspaceIndex> {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
let workspace = shell
|
let active = shell.workspaces.active_num(¤t_output).1;
|
||||||
.workspaces
|
let workspace = active.checked_sub(1).unwrap_or(
|
||||||
.active_num(¤t_output)
|
shell
|
||||||
.1
|
.workspaces
|
||||||
.checked_sub(1)
|
.len(¤t_output)
|
||||||
.ok_or(InvalidWorkspaceIndex)?;
|
.checked_sub(1)
|
||||||
|
.ok_or(InvalidWorkspaceIndex)?,
|
||||||
|
);
|
||||||
|
|
||||||
|
if workspace == active {
|
||||||
|
return Err(InvalidWorkspaceIndex);
|
||||||
|
}
|
||||||
|
|
||||||
shell.activate(
|
shell.activate(
|
||||||
¤t_output,
|
¤t_output,
|
||||||
workspace,
|
workspace,
|
||||||
if gesture {
|
if gesture {
|
||||||
WorkspaceDelta::new_gesture()
|
WorkspaceDelta::new_gesture(false)
|
||||||
} else {
|
} else {
|
||||||
WorkspaceDelta::new_shortcut()
|
WorkspaceDelta::new_shortcut()
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1056,10 +1056,12 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
match gesture_state.action {
|
match gesture_state.action {
|
||||||
Some(SwipeAction::NextWorkspace) | Some(SwipeAction::PrevWorkspace) => {
|
Some(x @ SwipeAction::NextWorkspace)
|
||||||
|
| Some(x @ SwipeAction::PrevWorkspace) => {
|
||||||
self.common.shell.write().update_workspace_delta(
|
self.common.shell.write().update_workspace_delta(
|
||||||
&seat.active_output(),
|
&seat.active_output(),
|
||||||
gesture_state.delta,
|
gesture_state.delta,
|
||||||
|
matches!(x, SwipeAction::NextWorkspace),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
||||||
|
|
@ -146,21 +146,32 @@ fn render_input_order_internal<R: 'static>(
|
||||||
};
|
};
|
||||||
let has_fullscreen = workspace.fullscreen.is_some();
|
let has_fullscreen = workspace.fullscreen.is_some();
|
||||||
|
|
||||||
let percentage = match start {
|
let (forward, percentage) = match start {
|
||||||
WorkspaceDelta::Shortcut(st) => ease(
|
WorkspaceDelta::Shortcut(st) => (
|
||||||
EaseInOutCubic,
|
*previous_idx < current.1,
|
||||||
0.0,
|
ease(
|
||||||
1.0,
|
EaseInOutCubic,
|
||||||
Instant::now().duration_since(*st).as_millis() as f32
|
0.0,
|
||||||
/ ANIMATION_DURATION.as_millis() as f32,
|
1.0,
|
||||||
|
Instant::now().duration_since(*st).as_millis() as f32
|
||||||
|
/ ANIMATION_DURATION.as_millis() as f32,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
WorkspaceDelta::Gesture {
|
||||||
|
percentage: prog,
|
||||||
|
forward,
|
||||||
|
} => (*forward, *prog as f32),
|
||||||
|
WorkspaceDelta::GestureEnd {
|
||||||
|
start,
|
||||||
|
spring,
|
||||||
|
forward,
|
||||||
|
} => (
|
||||||
|
*forward,
|
||||||
|
(spring.value_at(Instant::now().duration_since(*start)) as f32).clamp(0.0, 1.0),
|
||||||
),
|
),
|
||||||
WorkspaceDelta::Gesture(prog) => *prog as f32,
|
|
||||||
WorkspaceDelta::GestureEnd(st, spring) => {
|
|
||||||
(spring.value_at(Instant::now().duration_since(*st)) as f32).clamp(0.0, 1.0)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let offset = Point::<i32, Logical>::from(match (layout, *previous_idx < current.1) {
|
let offset = Point::<i32, Logical>::from(match (layout, forward) {
|
||||||
(WorkspaceLayout::Vertical, true) => {
|
(WorkspaceLayout::Vertical, true) => {
|
||||||
(0, (-output_size.h as f32 * percentage).round() as i32)
|
(0, (-output_size.h as f32 * percentage).round() as i32)
|
||||||
}
|
}
|
||||||
|
|
@ -177,7 +188,7 @@ fn render_input_order_internal<R: 'static>(
|
||||||
|
|
||||||
(
|
(
|
||||||
Some((previous, has_fullscreen, offset)),
|
Some((previous, has_fullscreen, offset)),
|
||||||
Point::<i32, Logical>::from(match (layout, *previous_idx < current.1) {
|
Point::<i32, Logical>::from(match (layout, forward) {
|
||||||
(WorkspaceLayout::Vertical, true) => (0, output_size.h + offset.y),
|
(WorkspaceLayout::Vertical, true) => (0, output_size.h + offset.y),
|
||||||
(WorkspaceLayout::Vertical, false) => (0, -(output_size.h - offset.y)),
|
(WorkspaceLayout::Vertical, false) => (0, -(output_size.h - offset.y)),
|
||||||
(WorkspaceLayout::Horizontal, true) => (output_size.w + offset.x, 0),
|
(WorkspaceLayout::Horizontal, true) => (output_size.w + offset.x, 0),
|
||||||
|
|
|
||||||
|
|
@ -301,28 +301,39 @@ pub struct SessionLock {
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum WorkspaceDelta {
|
pub enum WorkspaceDelta {
|
||||||
Shortcut(Instant),
|
Shortcut(Instant),
|
||||||
Gesture(f64),
|
Gesture {
|
||||||
GestureEnd(Instant, Spring),
|
percentage: f64,
|
||||||
|
forward: bool,
|
||||||
|
},
|
||||||
|
GestureEnd {
|
||||||
|
start: Instant,
|
||||||
|
spring: Spring,
|
||||||
|
forward: bool,
|
||||||
|
},
|
||||||
// InvalidGesture(f64), TODO
|
// InvalidGesture(f64), TODO
|
||||||
// InvalidGestureEnd(Instant, Spring), TODO
|
// InvalidGestureEnd(Instant, Spring), TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkspaceDelta {
|
impl WorkspaceDelta {
|
||||||
pub fn new_gesture() -> Self {
|
pub fn new_gesture(forward: bool) -> Self {
|
||||||
WorkspaceDelta::Gesture(0.0)
|
WorkspaceDelta::Gesture {
|
||||||
|
percentage: 0.0,
|
||||||
|
forward,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_gesture_end(delta: f64, velocity: f64) -> Self {
|
pub fn new_gesture_end(delta: f64, velocity: f64, forward: bool) -> Self {
|
||||||
let params: SpringParams = SpringParams::new(1.0, 1000.0, 0.0001);
|
let params: SpringParams = SpringParams::new(1.0, 1000.0, 0.0001);
|
||||||
WorkspaceDelta::GestureEnd(
|
WorkspaceDelta::GestureEnd {
|
||||||
Instant::now(),
|
start: Instant::now(),
|
||||||
Spring {
|
forward,
|
||||||
|
spring: Spring {
|
||||||
from: delta,
|
from: delta,
|
||||||
to: 1.0,
|
to: 1.0,
|
||||||
initial_velocity: velocity,
|
initial_velocity: velocity,
|
||||||
params,
|
params,
|
||||||
},
|
},
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_shortcut() -> Self {
|
pub fn new_shortcut() -> Self {
|
||||||
|
|
@ -332,7 +343,7 @@ impl WorkspaceDelta {
|
||||||
pub fn is_animating(&self) -> bool {
|
pub fn is_animating(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
WorkspaceDelta::Shortcut(_) | WorkspaceDelta::GestureEnd(_, _)
|
WorkspaceDelta::Shortcut(_) | WorkspaceDelta::GestureEnd { .. }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -497,8 +508,8 @@ impl WorkspaceSet {
|
||||||
} else {
|
} else {
|
||||||
// snap to workspace, when in between workspaces due to swipe gesture
|
// snap to workspace, when in between workspaces due to swipe gesture
|
||||||
if let Some((p_idx, p_delta)) = self.previously_active {
|
if let Some((p_idx, p_delta)) = self.previously_active {
|
||||||
if matches!(p_delta, WorkspaceDelta::Gesture(..))
|
if matches!(p_delta, WorkspaceDelta::Gesture { .. })
|
||||||
&& matches!(workspace_delta, WorkspaceDelta::GestureEnd(..))
|
&& matches!(workspace_delta, WorkspaceDelta::GestureEnd { .. })
|
||||||
{
|
{
|
||||||
self.previously_active = Some((p_idx, workspace_delta));
|
self.previously_active = Some((p_idx, workspace_delta));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -521,10 +532,16 @@ impl WorkspaceSet {
|
||||||
Err(InvalidWorkspaceIndex)
|
Err(InvalidWorkspaceIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_workspace_delta(&mut self, delta: f64) {
|
fn update_workspace_delta(&mut self, delta: f64, forward: bool) {
|
||||||
let easing = delta.clamp(0.0, GESTURE_MAX_LENGTH).abs() / GESTURE_MAX_LENGTH;
|
let easing = delta.clamp(0.0, GESTURE_MAX_LENGTH).abs() / GESTURE_MAX_LENGTH;
|
||||||
if let Some((idx, _)) = self.previously_active {
|
if let Some((idx, _)) = self.previously_active {
|
||||||
self.previously_active = Some((idx, WorkspaceDelta::Gesture(easing)));
|
self.previously_active = Some((
|
||||||
|
idx,
|
||||||
|
WorkspaceDelta::Gesture {
|
||||||
|
percentage: easing,
|
||||||
|
forward,
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -550,8 +567,9 @@ impl WorkspaceSet {
|
||||||
self.previously_active = None;
|
self.previously_active = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WorkspaceDelta::GestureEnd(st, spring) => {
|
WorkspaceDelta::GestureEnd { start, spring, .. } => {
|
||||||
if Instant::now().duration_since(st).as_millis() > spring.duration().as_millis()
|
if Instant::now().duration_since(start).as_millis()
|
||||||
|
> spring.duration().as_millis()
|
||||||
{
|
{
|
||||||
self.previously_active = None;
|
self.previously_active = None;
|
||||||
}
|
}
|
||||||
|
|
@ -1576,16 +1594,16 @@ impl Shell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_workspace_delta(&mut self, output: &Output, delta: f64) {
|
pub fn update_workspace_delta(&mut self, output: &Output, delta: f64, forward: bool) {
|
||||||
match &mut self.workspaces.mode {
|
match &mut self.workspaces.mode {
|
||||||
WorkspaceMode::OutputBound => {
|
WorkspaceMode::OutputBound => {
|
||||||
if let Some(set) = self.workspaces.sets.get_mut(output) {
|
if let Some(set) = self.workspaces.sets.get_mut(output) {
|
||||||
set.update_workspace_delta(delta);
|
set.update_workspace_delta(delta, forward);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WorkspaceMode::Global => {
|
WorkspaceMode::Global => {
|
||||||
for set in self.workspaces.sets.values_mut() {
|
for set in self.workspaces.sets.values_mut() {
|
||||||
set.update_workspace_delta(delta);
|
set.update_workspace_delta(delta, forward);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1606,19 +1624,34 @@ impl Shell {
|
||||||
) {
|
) {
|
||||||
set.workspaces[set.active].tiling_layer.cleanup_drag();
|
set.workspaces[set.active].tiling_layer.cleanup_drag();
|
||||||
}
|
}
|
||||||
if let Some((_, WorkspaceDelta::Gesture(delta))) = set.previously_active {
|
if let Some((
|
||||||
|
_,
|
||||||
|
WorkspaceDelta::Gesture {
|
||||||
|
percentage: delta,
|
||||||
|
forward,
|
||||||
|
},
|
||||||
|
)) = set.previously_active
|
||||||
|
{
|
||||||
if (velocity > 0.0 && velocity.abs() >= GESTURE_VELOCITY_THRESHOLD)
|
if (velocity > 0.0 && velocity.abs() >= GESTURE_VELOCITY_THRESHOLD)
|
||||||
|| (velocity.abs() < GESTURE_VELOCITY_THRESHOLD
|
|| (velocity.abs() < GESTURE_VELOCITY_THRESHOLD
|
||||||
&& delta.abs() > GESTURE_POSITION_THRESHOLD)
|
&& delta.abs() > GESTURE_POSITION_THRESHOLD)
|
||||||
{
|
{
|
||||||
set.activate(
|
set.activate(
|
||||||
set.active,
|
set.active,
|
||||||
WorkspaceDelta::new_gesture_end(delta.abs(), velocity.abs()),
|
WorkspaceDelta::new_gesture_end(
|
||||||
|
delta.abs(),
|
||||||
|
velocity.abs(),
|
||||||
|
forward,
|
||||||
|
),
|
||||||
workspace_state,
|
workspace_state,
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
set.activate_previous(
|
set.activate_previous(
|
||||||
WorkspaceDelta::new_gesture_end(1.0 - delta.abs(), velocity.abs()),
|
WorkspaceDelta::new_gesture_end(
|
||||||
|
1.0 - delta.abs(),
|
||||||
|
velocity.abs(),
|
||||||
|
!forward,
|
||||||
|
),
|
||||||
workspace_state,
|
workspace_state,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
@ -1635,19 +1668,34 @@ impl Shell {
|
||||||
}
|
}
|
||||||
WorkspaceMode::Global => {
|
WorkspaceMode::Global => {
|
||||||
for set in self.workspaces.sets.values_mut() {
|
for set in self.workspaces.sets.values_mut() {
|
||||||
if let Some((_, WorkspaceDelta::Gesture(delta))) = set.previously_active {
|
if let Some((
|
||||||
|
_,
|
||||||
|
WorkspaceDelta::Gesture {
|
||||||
|
percentage: delta,
|
||||||
|
forward,
|
||||||
|
},
|
||||||
|
)) = set.previously_active
|
||||||
|
{
|
||||||
if (velocity > 0.0 && velocity.abs() >= GESTURE_VELOCITY_THRESHOLD)
|
if (velocity > 0.0 && velocity.abs() >= GESTURE_VELOCITY_THRESHOLD)
|
||||||
|| (velocity.abs() < GESTURE_VELOCITY_THRESHOLD
|
|| (velocity.abs() < GESTURE_VELOCITY_THRESHOLD
|
||||||
&& delta.abs() > GESTURE_POSITION_THRESHOLD)
|
&& delta.abs() > GESTURE_POSITION_THRESHOLD)
|
||||||
{
|
{
|
||||||
set.activate(
|
set.activate(
|
||||||
set.active,
|
set.active,
|
||||||
WorkspaceDelta::new_gesture_end(delta.abs(), velocity.abs()),
|
WorkspaceDelta::new_gesture_end(
|
||||||
|
delta.abs(),
|
||||||
|
velocity.abs(),
|
||||||
|
forward,
|
||||||
|
),
|
||||||
workspace_state,
|
workspace_state,
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
set.activate_previous(
|
set.activate_previous(
|
||||||
WorkspaceDelta::new_gesture_end(1.0 - delta.abs(), velocity.abs()),
|
WorkspaceDelta::new_gesture_end(
|
||||||
|
1.0 - delta.abs(),
|
||||||
|
velocity.abs(),
|
||||||
|
!forward,
|
||||||
|
),
|
||||||
workspace_state,
|
workspace_state,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue