Use libcosmic DiscreteScrollState helper

This commit is contained in:
Ian Douglas Scott 2025-10-13 14:11:48 -07:00 committed by Ian Douglas Scott
parent cf2bb0205c
commit a607da7f44
2 changed files with 102 additions and 121 deletions

View file

@ -28,6 +28,7 @@ use cosmic::{
iced_winit::platform_specific::wayland::commands::layer_surface::{
destroy_layer_surface, get_layer_surface,
},
scroll::DiscreteScrollState,
};
use cosmic_comp_config::CosmicCompConfig;
use cosmic_config::{CosmicConfigEntry, cosmic_config_derive::CosmicConfigEntry};
@ -38,7 +39,7 @@ use std::{
mem,
path::PathBuf,
str,
time::{Duration, Instant},
time::Duration,
};
mod dbus;
@ -53,8 +54,7 @@ mod utils;
mod widgets;
use dnd::{DragSurface, DragToplevel, DragWorkspace, DropTarget};
// Number of scroll pixels before changing workspace
const SCROLL_PIXELS: f32 = 24.0;
const SCROLL_RATE_LIMIT: Duration = Duration::from_millis(200);
#[derive(Clone, Debug, Default, PartialEq, CosmicConfigEntry)]
struct CosmicWorkspacesConfig {
@ -86,11 +86,6 @@ impl CosmicFlags for Args {
}
}
enum ScrollDirection {
Next,
Prev,
}
#[derive(Clone, Debug)]
enum Msg {
WaylandEvent(WaylandEvent),
@ -200,7 +195,7 @@ struct App {
conf: Conf,
core: cosmic::app::Core,
drop_target: Option<DropTarget>,
scroll: Option<(f32, Instant)>,
scroll: DiscreteScrollState,
dbus_interface: Option<dbus::Interface>,
panel_configs: HashMap<String, Option<CosmicPanelConfig>>,
}
@ -415,6 +410,7 @@ impl Application for App {
(
Self {
core,
scroll: DiscreteScrollState::default().rate_limit(Some(SCROLL_RATE_LIMIT)),
..Default::default()
},
Task::none(),
@ -672,81 +668,20 @@ impl Application for App {
}
}
Msg::OnScroll(output, delta) => {
// Accumulate delta with a timer
// TODO: Should x scroll be handled too?
// Best time/pixel count?
let previous_scroll = if let Some((scroll, last_scroll_time)) = self.scroll {
if last_scroll_time.elapsed() > Duration::from_millis(100) {
0.
} else {
scroll
let discrete_delta = self.scroll.update(delta);
if discrete_delta.y != 0 {
// TODO assumes only one active workspace per output
let workspaces = self.workspaces.for_output(&output).collect::<Vec<_>>();
if let Some(workspace_idx) = workspaces.iter().position(|i| i.is_active()) {
// Add delta_num, to index wrapping around
let new_workspace_idx = (workspace_idx as isize - discrete_delta.y)
.rem_euclid(workspaces.len() as isize)
as usize;
let workspace = workspaces[new_workspace_idx];
self.send_wayland_cmd(backend::Cmd::ActivateWorkspace(
workspace.handle().clone(),
));
}
} else {
0.
};
let direction = match delta {
ScrollDelta::Pixels { x: _, mut y } => {
y = -y;
let scroll = previous_scroll + y;
if scroll <= -SCROLL_PIXELS {
self.scroll = None;
ScrollDirection::Prev
} else if scroll >= SCROLL_PIXELS {
self.scroll = None;
ScrollDirection::Next
} else {
// If scroll has y element, accumulate scroll
self.scroll = if y != 0. {
Some((scroll, Instant::now()))
} else {
None
};
return Task::none();
}
}
ScrollDelta::Lines { x: _, mut y } => {
y = -y;
let scroll = previous_scroll + y;
if scroll <= -1. {
self.scroll = None;
ScrollDirection::Prev
} else if scroll >= 1. {
self.scroll = None;
ScrollDirection::Next
} else {
self.scroll = if y != 0. {
Some((scroll, Instant::now()))
} else {
None
};
return Task::none();
}
}
};
// TODO assumes only one active workspace per output
let workspaces = self.workspaces.for_output(&output).collect::<Vec<_>>();
if let Some(workspace_idx) = workspaces.iter().position(|i| i.is_active()) {
let new_workspace_idx = match direction {
// Next workspace on output, wrapping to start
ScrollDirection::Next => (workspace_idx + 1) % workspaces.len(),
// Previous workspace on output, wrapping to end
ScrollDirection::Prev => {
if workspace_idx == 0 {
workspaces.len() - 1
} else {
workspace_idx - 1
}
}
};
let workspace = workspaces[new_workspace_idx];
self.send_wayland_cmd(backend::Cmd::ActivateWorkspace(
workspace.handle().clone(),
));
}
}
Msg::DndWorkspaceDrag => {}