Compare commits

..

No commits in common. "934db8277555e8c6c6ec38b34c5097fcefeb7295" and "61149d95d01d7ee84295841b55b2c2af1e73c593" have entirely different histories.

13 changed files with 360 additions and 1785 deletions

1315
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -17,18 +17,18 @@ cosmic-comp-config = { path = "cosmic-comp-config", features = [
"libdisplay-info",
"output",
] }
cosmic-config = { path = "../libcosmic/cosmic-config", features = [
cosmic-config = { git = "https://github.com/pop-os/libcosmic", features = [
"calloop",
"macro",
] }
cosmic-protocols = { path = "../cosmic-protocols", default-features = false, features = [
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", rev = "160b086", default-features = false, features = [
"server",
] }
cosmic-settings-config = { path = "../cosmic-settings-daemon/config" }
cosmic-settings-daemon-config = { path = "../cosmic-settings-daemon/cosmic-settings-daemon-config", features = [
cosmic-settings-config = { git = "https://github.com/pop-os/cosmic-settings-daemon" }
cosmic-settings-daemon-config = { git = "https://github.com/pop-os/cosmic-settings-daemon", features = [
"greeter",
] }
cosmic-text = { git = "https://forge.aditua.com/leyoda/cosmic-text.git", branch = "local/pr-503", features = [
cosmic-text = { git = "https://github.com/pop-os/cosmic-text.git", features = [
"shape-run-cache",
] }
libdisplay-info = "0.3.0"
@ -39,14 +39,10 @@ i18n-embed = { version = "0.16", features = [
"desktop-requester",
] }
i18n-embed-fl = "0.10"
iced_tiny_skia = { path = "../libcosmic/iced/tiny_skia" }
iced_tiny_skia = { git = "https://github.com/pop-os/libcosmic" }
indexmap = "2.13"
keyframe = "1.1.1"
cosmic = { package = "libcosmic-yoda", path = "../libcosmic", default-features = false, features = [
"tokio",
"wayland",
"multi-window",
] }
libcosmic = { git = "https://github.com/pop-os/libcosmic", default-features = false }
libsystemd = { version = "0.7", optional = true }
log-panics = { version = "2", features = ["with-backtrace"] }
ordered-float = "5.1"
@ -142,36 +138,9 @@ inherits = "release"
[profile.release]
lto = "fat"
[patch.'https://github.com/pop-os/libcosmic']
cosmic-config = { path = "../libcosmic/cosmic-config" }
cosmic-theme = { path = "../libcosmic/cosmic-theme" }
iced = { path = "../libcosmic/iced" }
iced_accessibility = { path = "../libcosmic/iced/accessibility" }
iced_core = { path = "../libcosmic/iced/core" }
iced_futures = { path = "../libcosmic/iced/futures" }
iced_graphics = { path = "../libcosmic/iced/graphics" }
iced_renderer = { path = "../libcosmic/iced/renderer" }
iced_runtime = { path = "../libcosmic/iced/runtime" }
iced_tiny_skia = { path = "../libcosmic/iced/tiny_skia" }
iced_wgpu = { path = "../libcosmic/iced/wgpu" }
iced_widget = { path = "../libcosmic/iced/widget" }
iced_winit = { path = "../libcosmic/iced/winit" }
[patch.'https://github.com/pop-os/cosmic-protocols']
cosmic-protocols = { path = "../cosmic-protocols" }
cosmic-client-toolkit = { path = "../cosmic-protocols/client-toolkit" }
[patch.'https://github.com/pop-os/cosmic-settings-daemon']
cosmic-settings-config = { path = "../cosmic-settings-daemon/config" }
cosmic-settings-daemon-config = { path = "../cosmic-settings-daemon/cosmic-settings-daemon-config" }
[patch.'https://github.com/pop-os/cosmic-text.git']
cosmic-text = { git = "https://forge.aditua.com/leyoda/cosmic-text.git", branch = "local/pr-503" }
[patch.'https://forge.aditua.com/leyoda/window_clipboard.git']
window_clipboard = { path = "../window_clipboard" }
dnd = { path = "../window_clipboard/dnd" }
mime = { path = "../window_clipboard/mime" }
[patch."https://github.com/pop-os/cosmic-protocols"]
cosmic-protocols = { git = "https://github.com/pop-os//cosmic-protocols", branch = "main" }
cosmic-client-toolkit = { git = "https://github.com/pop-os//cosmic-protocols", branch = "main" }
[patch.crates-io]
smithay = { git = "https://github.com/smithay/smithay.git", rev = "774f2ab" }

View file

@ -4,8 +4,8 @@ version = "1.0.0"
edition = "2024"
[dependencies]
cosmic-config = { path = "../../libcosmic/cosmic-config" }
cosmic-randr-shell = { path = "../../cosmic-randr/shell", optional = true }
cosmic-config = { git = "https://github.com/pop-os/libcosmic/" }
cosmic-randr-shell = { git = "https://github.com/pop-os/cosmic-randr/", optional = true }
input = "0.10.0"
libdisplay-info = { version = "0.3.0", optional = true }
serde = { version = "1", features = ["derive"] }

View file

@ -99,8 +99,6 @@ pub struct CosmicCompConfig {
pub edge_snap_threshold: u32,
pub accessibility_zoom: ZoomConfig,
pub appearance_settings: AppearanceConfig,
/// Hide the cursor after this many seconds of pointer inactivity (None disables)
pub cursor_hide_timeout: Option<u32>,
}
impl Default for CosmicCompConfig {
@ -137,7 +135,6 @@ impl Default for CosmicCompConfig {
edge_snap_threshold: 0,
accessibility_zoom: ZoomConfig::default(),
appearance_settings: AppearanceConfig::default(),
cursor_hide_timeout: None,
}
}
}

View file

@ -28,7 +28,7 @@ use smithay::{
},
egl::{EGLContext, EGLDevice, EGLDisplay, context::ContextPriority},
renderer::glow::GlowRenderer,
session::{Session, libseat::LibSeatSession},
session::Session,
},
desktop::utils::OutputPresentationFeedback,
output::{Mode as OutputMode, Output, PhysicalProperties, Scale, Subpixel},
@ -40,10 +40,7 @@ use smithay::{
wayland_server::DisplayHandle,
},
utils::{Clock, DevPath, DeviceFd, Monotonic, Point, Transform},
wayland::{
drm_lease::{DrmLease, DrmLeaseState},
drm_syncobj::supports_syncobj_eventfd,
},
wayland::drm_lease::{DrmLease, DrmLeaseState},
};
use tracing::{error, info, warn};
use wayland_backend::server::ClientId;
@ -102,20 +99,6 @@ pub struct Device {
pub socket: Option<Socket>,
}
#[derive(Debug)]
struct ReusableDevice {
leasing_global: Option<DrmLeaseState>,
active_clients: HashSet<ClientId>,
socket: Option<Socket>,
}
#[derive(Debug)]
struct OldDeviceState {
fd: DeviceFd,
outputs: HashMap<connector::Handle, Output>,
leased_connectors: HashSet<connector::Handle>,
}
#[derive(Debug)]
pub struct LockedDevice<'a> {
pub inner: &'a mut InnerDevice,
@ -239,14 +222,138 @@ impl State {
}
}
let mut device = Device::new(
dev,
path,
&mut self.backend.kms().session,
&mut self.common,
dh,
None,
)?;
let fd = DrmDeviceFd::new(DeviceFd::from(
self.backend
.kms()
.session
.open(
path,
OFlags::RDWR | OFlags::CLOEXEC | OFlags::NOCTTY | OFlags::NONBLOCK,
)
.with_context(|| {
format!(
"Failed to optain file descriptor for drm device: {}",
path.display()
)
})?,
));
let (drm, notifier) = DrmDevice::new(fd.clone(), false)
.with_context(|| format!("Failed to initialize drm device for: {}", path.display()))?;
let drm_node = DrmNode::from_dev_id(dev)?;
let supports_atomic = drm.is_atomic();
let gbm = GbmDevice::new(fd)
.with_context(|| format!("Failed to initialize GBM device for {}", path.display()))?;
let (render_node, render_formats, texture_formats, is_software) = {
let egl = init_egl(&gbm)?;
let render_node = egl
.device
.try_get_render_node()
.ok()
.and_then(std::convert::identity)
.unwrap_or(drm_node);
let render_formats = egl.context.dmabuf_render_formats().clone();
let texture_formats = egl.context.dmabuf_texture_formats().clone();
(
render_node,
render_formats,
texture_formats,
egl.device.is_software(),
)
};
let token = self
.common
.event_loop_handle
.insert_source(
notifier,
move |event, metadata, state: &mut State| match event {
DrmEvent::VBlank(crtc) => {
if let Some(device) = state.backend.kms().drm_devices.get_mut(&drm_node)
&& let Some(surface) = device.inner.surfaces.get_mut(&crtc)
{
surface.on_vblank(metadata.take());
}
}
DrmEvent::Error(err) => {
warn!(?err, "Failed to read events of device {:?}.", dev);
}
},
)
.with_context(|| format!("Failed to add drm device to event loop: {}", dev))?;
let socket = match (!is_software)
.then(|| self.create_socket(dh, render_node, texture_formats.clone()))
.transpose()
{
Ok(socket) => socket,
Err(err) => {
warn!(
?err,
"Failed to initialize hardware-acceleration for clients on {}.", render_node,
);
None
}
};
let leasing_global = match (!is_software)
.then(|| DrmLeaseState::new::<State>(dh, &drm_node))
.transpose()
{
Ok(global) => global,
Err(err) => {
// TODO: replace with inspect_err, once stable
warn!(
?err,
"Failed to initialize drm lease global for: {}", drm_node
);
None
}
};
let drm = GbmDrmOutputManager::new(
drm,
GbmAllocator::new(
gbm.clone(),
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
),
GbmFramebufferExporter::new(gbm.clone(), render_node.into()),
Some(gbm.clone()),
[
Fourcc::Abgr2101010,
Fourcc::Argb2101010,
Fourcc::Abgr8888,
Fourcc::Argb8888,
],
render_formats,
);
let mut device = Device {
drm,
inner: InnerDevice {
dev_node: drm_node,
render_node,
is_software,
egl: None,
outputs: HashMap::new(),
surfaces: HashMap::new(),
gbm,
leased_connectors: Vec::new(),
leasing_global,
active_leases: Vec::new(),
active_clients: HashSet::new(),
},
supports_atomic,
texture_formats,
event_token: Some(token),
socket,
};
let connectors = device.enumerate_surfaces()?.added; // There are no removed outputs on newly added devices
let mut wl_outputs = Vec::new();
let mut w = self.common.shell.read().global_space().size.w as u32;
@ -280,7 +387,7 @@ impl State {
// TODO atomic commit all surfaces together and drop surfaces, if it fails due to bandwidth
let kms = self.backend.kms();
kms.drm_devices.insert(device.inner.dev_node, device);
kms.drm_devices.insert(drm_node, device);
}
self.common
@ -382,218 +489,6 @@ impl State {
Ok(outputs_added)
}
pub fn reopen_device(
&mut self,
dev: dev_t,
path: &Path,
dh: &DisplayHandle,
) -> Result<Vec<Output>> {
let backend = self.backend.kms();
let drm_node = backend
.drm_devices
.values()
.find_map(|device| {
(device.inner.dev_node.dev_id() == dev).then_some(device.inner.dev_node)
})
.with_context(|| format!("Couldn't find drm node for {}", dev))?;
if let Some(mut device) = backend.drm_devices.shift_remove(&drm_node) {
let is_primary = backend
.primary_node
.read()
.unwrap()
.is_some_and(|node| node == device.inner.render_node);
// all drm resources become inert
if let Some(token) = device.event_token.take() {
self.common.event_loop_handle.remove(token);
}
for (_, surface) in device.inner.surfaces.drain() {
surface.drop_and_join();
}
if let Some(leasing_global) = device.inner.leasing_global.as_mut() {
for (connector, _) in &device.inner.leased_connectors {
leasing_global.withdraw_connector(*connector);
}
device.inner.active_leases.clear();
}
// These contain a reference to the file descriptor
backend.api.as_mut().remove_node(&device.inner.render_node);
// trigger enumeration
let _ = backend.api.devices();
for surface in backend
.drm_devices
.values_mut()
.flat_map(|device| device.inner.surfaces.values_mut())
{
surface.remove_node(device.inner.render_node);
}
let syncobj_guard =
if is_primary && let Some(syncobj_state) = backend.syncobj_state.as_mut() {
Some(syncobj_state.close_device())
} else {
None
};
let (reusable, mut old_state) = device.reuse();
match TryInto::<OwnedFd>::try_into(old_state.fd) {
Ok(fd) => {
if let Err(err) = backend.session.close(fd) {
warn!("Failed to close drm device fd: {}", err);
}
}
Err(_) => {
warn!(?drm_node, "Unable to close drm device fd cleanly.");
}
};
let mut new_device = Device::new(
dev,
path,
&mut backend.session,
&mut self.common,
dh,
Some(reusable),
)?;
if let Some(guard) = syncobj_guard {
let import_device = new_device.drm.device().device_fd().clone();
if supports_syncobj_eventfd(&import_device) {
guard.update_device(import_device);
} else {
drop(guard);
dh.remove_global::<State>(backend.syncobj_state.take().unwrap().into_global());
}
}
let connectors = new_device.enumerate_surfaces()?.added;
let mut outputs_added = Vec::new();
let mut w = self.common.shell.read().global_space().size.w as u32;
{
for (conn, maybe_crtc) in connectors {
if let Some(output) = old_state.outputs.remove(&conn) {
let has_surface = if old_state.leased_connectors.contains(&conn) {
if let Some(crtc) = maybe_crtc {
new_device.inner.leased_connectors.push((conn, crtc));
info!(
"Connector {} is non-desktop, setting up for leasing",
output.name()
);
if let Some(lease_state) = new_device.inner.leasing_global.as_mut()
{
let physical = output.physical_properties();
lease_state.add_connector::<State>(
conn,
output.name(),
format!("{} {}", physical.make, physical.model),
);
}
} else {
warn!(
"Connector {} is non-desktop, but we don't have a free crtc: not leasing",
output.name()
);
}
false
} else {
let loc = output.current_location();
populate_modes(
new_device.drm.device_mut(),
&output,
conn,
true,
(loc.x as u32, loc.y as u32),
)
.with_context(|| "Failed to enumerate connector modes")?;
if let Some(crtc) = maybe_crtc {
match Surface::new(
&output,
crtc,
conn,
backend.primary_node.clone(),
new_device.inner.dev_node,
new_device.inner.render_node,
&self.common.event_loop_handle,
self.common.config.dynamic_conf.screen_filter().clone(),
self.common.shell.clone(),
self.common.startup_done.clone(),
) {
Ok(data) => {
new_device.inner.surfaces.insert(crtc, data);
true
}
Err(err) => {
error!(?crtc, "Failed to initialize surface: {}", err);
false
}
}
} else {
false
}
};
if !has_surface {
output
.user_data()
.get::<RefCell<OutputConfig>>()
.unwrap()
.borrow_mut()
.enabled = OutputState::Disabled;
}
new_device.inner.outputs.insert(conn, output);
} else {
match new_device.inner.connector_added(
new_device.drm.device_mut(),
backend.primary_node.clone(),
conn,
maybe_crtc,
(w, 0),
&self.common.event_loop_handle,
self.common.config.dynamic_conf.screen_filter().clone(),
self.common.shell.clone(),
self.common.startup_done.clone(),
) {
Ok((output, should_expose)) => {
if should_expose {
w += output.geometry().size.w as u32;
outputs_added.push(output.clone());
}
new_device.inner.outputs.insert(conn, output);
}
Err(err) => {
warn!(?err, "Failed to initialize output, skipping");
}
}
}
}
}
self.common
.output_configuration_state
.remove_heads(old_state.outputs.values());
self.common
.output_configuration_state
.add_heads(outputs_added.iter());
for output in old_state.outputs.values() {
self.common.remove_output(output);
}
backend.drm_devices.insert(drm_node, new_device);
backend.refresh_used_devices()?;
Ok(outputs_added)
} else {
Ok(Vec::new())
}
}
pub fn device_removed(&mut self, dev: dev_t, dh: &DisplayHandle) -> Result<()> {
let backend = self.backend.kms();
// we can't use DrmNode::from_node_id, because that assumes the node is still on sysfs
@ -686,158 +581,6 @@ pub struct OutputChanges {
}
impl Device {
fn new(
dev: dev_t,
path: impl AsRef<Path>,
session: &mut LibSeatSession,
common: &mut Common,
dh: &DisplayHandle,
reuse: Option<ReusableDevice>,
) -> Result<Self> {
let path = path.as_ref();
let fd = DrmDeviceFd::new(DeviceFd::from(
session
.open(
path,
OFlags::RDWR | OFlags::CLOEXEC | OFlags::NOCTTY | OFlags::NONBLOCK,
)
.with_context(|| {
format!(
"Failed to optain file descriptor for drm device: {}",
path.display()
)
})?,
));
let (drm, notifier) = DrmDevice::new(fd.clone(), false)
.with_context(|| format!("Failed to initialize drm device for: {}", path.display()))?;
let dev_node = DrmNode::from_dev_id(dev)?;
let supports_atomic = drm.is_atomic();
let gbm = GbmDevice::new(fd)
.with_context(|| format!("Failed to initialize GBM device for {}", path.display()))?;
let (render_node, render_formats, texture_formats, is_software) = {
let egl = init_egl(&gbm)?;
let render_node = egl
.device
.try_get_render_node()
.ok()
.and_then(std::convert::identity)
.unwrap_or(dev_node);
let render_formats = egl.context.dmabuf_render_formats().clone();
let texture_formats = egl.context.dmabuf_texture_formats().clone();
(
render_node,
render_formats,
texture_formats,
egl.device.is_software(),
)
};
let token = common
.event_loop_handle
.insert_source(
notifier,
move |event, metadata, state: &mut State| match event {
DrmEvent::VBlank(crtc) => {
if let Some(device) = state.backend.kms().drm_devices.get_mut(&dev_node)
&& let Some(surface) = device.inner.surfaces.get_mut(&crtc)
{
surface.on_vblank(metadata.take());
}
}
DrmEvent::Error(err) => {
warn!(?err, "Failed to read events of device {:?}.", dev);
}
},
)
.with_context(|| format!("Failed to add drm device to event loop: {}", dev))?;
let ReusableDevice {
leasing_global,
active_clients,
socket,
} = reuse.unwrap_or_else(|| {
let socket = match (!is_software)
.then(|| common.create_socket(dh, render_node, texture_formats.clone()))
.transpose()
{
Ok(socket) => socket,
Err(err) => {
warn!(
?err,
"Failed to initialize hardware-acceleration for clients on {}.",
render_node,
);
None
}
};
let leasing_global = match (!is_software)
.then(|| DrmLeaseState::new::<State>(dh, &dev_node))
.transpose()
{
Ok(global) => global,
Err(err) => {
// TODO: replace with inspect_err, once stable
warn!(
?err,
"Failed to initialize drm lease global for: {}", dev_node
);
None
}
};
ReusableDevice {
leasing_global,
active_clients: HashSet::new(),
socket,
}
});
let drm = GbmDrmOutputManager::new(
drm,
GbmAllocator::new(
gbm.clone(),
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
),
GbmFramebufferExporter::new(gbm.clone(), render_node.into()),
Some(gbm.clone()),
[
Fourcc::Abgr2101010,
Fourcc::Argb2101010,
Fourcc::Abgr8888,
Fourcc::Argb8888,
],
render_formats,
);
Ok(Device {
drm,
inner: InnerDevice {
dev_node,
render_node,
is_software,
egl: None,
outputs: HashMap::new(),
surfaces: HashMap::new(),
gbm,
leased_connectors: Vec::new(),
leasing_global,
active_leases: Vec::new(),
active_clients,
},
supports_atomic,
texture_formats,
event_token: Some(token),
socket,
})
}
pub fn enumerate_surfaces(&mut self) -> Result<OutputChanges> {
// enumerate our outputs
let config =
@ -891,27 +634,6 @@ impl Device {
drm: self.drm.lock(),
}
}
fn reuse(self) -> (ReusableDevice, OldDeviceState) {
let device = ReusableDevice {
leasing_global: self.inner.leasing_global,
active_clients: self.inner.active_clients,
socket: self.socket,
};
let state = OldDeviceState {
fd: self.drm.device().device_fd().device_fd(),
outputs: self.inner.outputs,
leased_connectors: self
.inner
.leased_connectors
.iter()
.map(|(conn, _)| *conn)
.collect(),
};
(device, state)
}
}
impl LockedDevice<'_> {

View file

@ -394,37 +394,15 @@ impl State {
continue;
}
};
let dh = state.common.display_handle.clone();
if state.backend.kms().drm_devices.contains_key(&drm_node) {
match state.device_changed(dev) {
Ok(outputs) => added.extend(outputs),
Err(err) => {
error!(
?err,
"Failed to update drm device {}. Re-opening",
path.display(),
);
match state.reopen_device(dev, path, &dh) {
Ok(outputs) => added.extend(outputs),
Err(err) => {
error!(
?err,
"Failed to re-open drm device {}. Device lost",
path.display(),
);
if let Err(err) = state.device_removed(dev, &dh) {
error!(
?err,
"Failed to close drm device {}.",
path.display(),
);
};
}
}
error!(?err, "Failed to update drm device {}.", path.display(),)
}
}
} else {
let dh = state.common.display_handle.clone();
match state.device_added(dev, path, &dh) {
Ok(outputs) => added.extend(outputs),
Err(err) => error!(?err, "Failed to add drm device {}.", path.display(),),

View file

@ -18,7 +18,7 @@ use smithay::{
use std::sync::Arc;
use tracing::{info, warn};
use crate::state::{ClientState, Common, State, advertised_node_for_client};
use crate::state::{ClientState, State, advertised_node_for_client};
#[derive(Debug)]
pub struct Socket {
@ -27,7 +27,7 @@ pub struct Socket {
pub dmabuf_global: DmabufGlobal,
}
impl Common {
impl State {
pub(super) fn create_socket(
&mut self,
dh: &DisplayHandle,
@ -36,7 +36,7 @@ impl Common {
) -> Result<Socket> {
let socket_name = format!(
"{}-{}",
&self.socket.to_string_lossy(),
&self.common.socket.to_string_lossy(),
render_node
.dev_path()
.unwrap()
@ -53,28 +53,33 @@ impl Common {
.with_context(|| "Failed to create drm format shared memory table")?;
let dmabuf_global = self
.common
.dmabuf_state
.create_global_with_filter_and_default_feedback::<State, _>(dh, &feedback, filter);
let drm_global_id = self.wl_drm_state.create_global_with_filter::<State, _>(
dh,
render_node
.dev_path_with_type(NodeType::Render)
.or_else(|| render_node.dev_path())
.ok_or(anyhow!(
"Could not determine path for gpu node: {}",
render_node
))?,
formats,
&dmabuf_global,
filter,
);
let drm_global_id = self
.common
.wl_drm_state
.create_global_with_filter::<State, _>(
dh,
render_node
.dev_path_with_type(NodeType::Render)
.or_else(|| render_node.dev_path())
.ok_or(anyhow!(
"Could not determine path for gpu node: {}",
render_node
))?,
formats,
&dmabuf_global,
filter,
);
// add a special socket for the gpu
let listener = ListeningSocketSource::with_name(&socket_name)
.with_context(|| format!("Failed to bind socket to {}", socket_name))?;
let socket_name_clone = socket_name.clone();
let token = self
.common
.event_loop_handle
.insert_source(listener, move |client_stream, _, state: &mut State| {
if let Err(err) = state.common.display_handle.insert_client(

View file

@ -464,7 +464,7 @@ impl Surface {
pub fn drop_and_join(mut self) {
let thread = self.thread.take();
std::mem::drop(self);
let _ = self;
if let Some(thread) = thread {
let name = thread.thread().name().unwrap().to_string();
let _ = thread.join();

View file

@ -17,25 +17,14 @@ use smithay::{
Seat,
pointer::{CursorIcon, CursorImageAttributes, CursorImageStatus},
},
reexports::{
calloop::{
RegistrationToken,
timer::{TimeoutAction, Timer},
},
wayland_server::protocol::wl_surface,
},
reexports::wayland_server::protocol::wl_surface,
render_elements,
utils::{
Buffer as BufferCoords, Logical, Monotonic, Physical, Point, Scale, Size, Time, Transform,
},
wayland::compositor::{get_role, with_states},
};
use std::{
collections::HashMap,
io::Read,
sync::Mutex,
time::{Duration, Instant},
};
use std::{collections::HashMap, io::Read, sync::Mutex};
use tracing::warn;
use xcursor::{
CursorTheme,
@ -207,10 +196,6 @@ pub struct CursorStateInner {
cursors: HashMap<CursorIcon, Cursor>,
current_image: Option<Image>,
image_cache: Vec<(Image, MemoryRenderBuffer)>,
hidden: bool,
idle_timer: Option<RegistrationToken>,
last_armed: Option<Instant>,
}
impl CursorStateInner {
@ -261,10 +246,6 @@ impl Default for CursorStateInner {
cursors: HashMap::new(),
current_image: None,
image_cache: Vec::new(),
hidden: false,
idle_timer: None,
last_armed: None,
}
}
}
@ -290,10 +271,6 @@ where
let mut state_ref = seat_userdata.get::<CursorState>().unwrap().lock().unwrap();
let state = &mut *state_ref;
if state.hidden {
return Vec::new();
}
let named_cursor = state.current_cursor.or(match cursor_status {
CursorImageStatus::Named(named_cursor) => Some(named_cursor),
_ => None,
@ -358,71 +335,3 @@ where
Vec::new()
}
}
const ACTIVITY_THROTTLE: Duration = Duration::from_millis(100);
/// Reveal the cursor and (re)arm the idle-hide timer; returns true if it was previously hidden
pub fn notify_cursor_activity(state: &State, seat: &Seat<State>) -> bool {
let timeout = state.common.config.cosmic_conf.cursor_hide_timeout;
let loop_handle = &state.common.event_loop_handle;
let cursor_state = seat.user_data().get::<CursorState>().unwrap();
let now = Instant::now();
let (was_hidden, old_token) = {
let mut inner = cursor_state.lock().unwrap();
let was_hidden = inner.hidden;
inner.hidden = false;
let throttled = timeout.is_some()
&& !was_hidden
&& inner.idle_timer.is_some()
&& inner
.last_armed
.is_some_and(|t| now.duration_since(t) < ACTIVITY_THROTTLE);
if throttled {
return was_hidden;
}
let old_token = inner.idle_timer.take();
inner.last_armed = None;
(was_hidden, old_token)
};
if let Some(token) = old_token {
loop_handle.remove(token);
}
if let Some(secs) = timeout {
let timer = Timer::from_duration(Duration::from_secs(secs as u64));
let seat = seat.clone();
if let Ok(token) = loop_handle.insert_source(timer, move |_, _, state| {
hide_cursor(state, &seat);
TimeoutAction::Drop
}) {
let mut inner = cursor_state.lock().unwrap();
inner.idle_timer = Some(token);
inner.last_armed = Some(now);
}
}
was_hidden
}
fn hide_cursor(state: &mut State, seat: &Seat<State>) {
if let Some(ptr) = seat.get_pointer()
&& ptr.is_grabbed()
{
return;
}
let cursor_state = seat.user_data().get::<CursorState>().unwrap();
{
let mut inner = cursor_state.lock().unwrap();
inner.hidden = true;
inner.idle_timer = None;
inner.last_armed = None;
}
let outputs: Vec<_> = state.common.shell.read().outputs().cloned().collect();
for output in outputs {
state.backend.schedule_render(&output);
}
}

View file

@ -947,25 +947,6 @@ fn config_changed(config: cosmic_config::Config, keys: Vec<String>, state: &mut
}
}
}
"cursor_hide_timeout" => {
let new = get_config::<Option<u32>>(&config, "cursor_hide_timeout");
if new != state.common.config.cosmic_conf.cursor_hide_timeout {
state.common.config.cosmic_conf.cursor_hide_timeout = new;
let seats: Vec<_> = state.common.shell.read().seats.iter().cloned().collect();
let mut needs_render = false;
for seat in seats {
needs_render |=
crate::backend::render::cursor::notify_cursor_activity(state, &seat);
}
if needs_render {
let outputs: Vec<_> =
state.common.shell.read().outputs().cloned().collect();
for output in outputs {
state.backend.schedule_render(&output);
}
}
}
}
_ => {}
}
}

View file

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::{
backend::render::{ElementFilter, cursor::notify_cursor_activity},
backend::render::ElementFilter,
config::{
Action, Config, PrivateAction,
key_bindings::{
@ -37,12 +37,11 @@ use cosmic_settings_config::shortcuts;
use cosmic_settings_config::shortcuts::action::{Direction, ResizeDirection};
use smithay::{
backend::input::{
AbsolutePositionEvent, Axis, AxisRelativeDirection, AxisSource, Device, DeviceCapability,
GestureBeginEvent, GestureEndEvent, GesturePinchUpdateEvent as _,
GestureSwipeUpdateEvent as _, InputBackend, InputEvent, KeyState, KeyboardKeyEvent,
PointerAxisEvent, ProximityState, Switch, SwitchState, SwitchToggleEvent,
TabletToolButtonEvent, TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent,
TabletToolTipState, TouchEvent,
AbsolutePositionEvent, Axis, AxisSource, Device, DeviceCapability, GestureBeginEvent,
GestureEndEvent, GesturePinchUpdateEvent as _, GestureSwipeUpdateEvent as _, InputBackend,
InputEvent, KeyState, KeyboardKeyEvent, PointerAxisEvent, ProximityState, Switch,
SwitchState, SwitchToggleEvent, TabletToolButtonEvent, TabletToolEvent,
TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TouchEvent,
},
desktop::{PopupKeyboardGrab, WindowSurfaceType, utils::under_from_surface_tree},
input::{
@ -309,7 +308,6 @@ impl State {
let shell = self.common.shell.write();
if let Some(seat) = shell.seats.for_device(&event.device()).cloned() {
self.common.idle_notifier_state.notify_activity(&seat);
notify_cursor_activity(self, &seat);
let current_output = seat.active_output();
let mut position = seat.get_pointer().unwrap().current_location().as_global();
@ -623,7 +621,6 @@ impl State {
.cloned();
if let Some(seat) = maybe_seat {
self.common.idle_notifier_state.notify_activity(&seat);
notify_cursor_activity(self, &seat);
let output = seat.active_output();
let geometry = output.geometry();
let position = geometry.loc.to_f64()
@ -690,7 +687,6 @@ impl State {
return;
};
self.common.idle_notifier_state.notify_activity(&seat);
notify_cursor_activity(self, &seat);
let current_focus = seat.get_keyboard().unwrap().current_focus();
let shortcuts_inhibited = current_focus.as_ref().is_some_and(|f| {
@ -902,7 +898,6 @@ impl State {
.cloned();
if let Some(seat) = maybe_seat {
self.common.idle_notifier_state.notify_activity(&seat);
notify_cursor_activity(self, &seat);
if seat.get_keyboard().unwrap().modifier_state().logo
&& self
@ -919,12 +914,6 @@ impl State {
.or_else(|| event.amount(Axis::Vertical))
.map(|val| val * scroll_factor)
{
if event.relative_direction(Axis::Vertical)
== AxisRelativeDirection::Inverted
{
percentage *= -1.;
}
if event.source() == AxisSource::Wheel {
percentage *= 5.;
}
@ -1371,7 +1360,6 @@ impl State {
let shell = self.common.shell.write();
if let Some(seat) = shell.seats.for_device(&event.device()).cloned() {
self.common.idle_notifier_state.notify_activity(&seat);
notify_cursor_activity(self, &seat);
let Some(output) =
mapped_output_for_device(&self.common.config, &shell, &event.device())
.cloned()
@ -1437,7 +1425,6 @@ impl State {
let shell = self.common.shell.write();
if let Some(seat) = shell.seats.for_device(&event.device()).cloned() {
self.common.idle_notifier_state.notify_activity(&seat);
notify_cursor_activity(self, &seat);
let Some(output) =
mapped_output_for_device(&self.common.config, &shell, &event.device())
.cloned()
@ -1499,7 +1486,6 @@ impl State {
.cloned();
if let Some(seat) = maybe_seat {
self.common.idle_notifier_state.notify_activity(&seat);
notify_cursor_activity(self, &seat);
if let Some(tool) = seat.tablet_seat().get_tool(&event.tool()) {
match event.tip_state() {
TabletToolTipState::Down => {
@ -1522,7 +1508,6 @@ impl State {
.cloned();
if let Some(seat) = maybe_seat {
self.common.idle_notifier_state.notify_activity(&seat);
notify_cursor_activity(self, &seat);
if let Some(tool) = seat.tablet_seat().get_tool(&event.tool()) {
tool.button(
event.button(),

View file

@ -9,7 +9,7 @@ use cosmic::{
};
use cosmic_comp_config::ZoomMovement;
use cosmic_config::ConfigSet;
use keyframe::{ease, functions::Linear};
use keyframe::{ease, functions::EaseInOutCubic};
use smithay::{
backend::renderer::{ImportMem, Renderer, element::AsRenderElements},
desktop::space::SpaceElement,
@ -135,7 +135,7 @@ impl OutputZoomState {
let percentage =
duration_since.as_millis() as f32 / ANIMATION_DURATION.as_millis() as f32;
ease(
Linear,
EaseInOutCubic,
EasePoint(*old_point),
EasePoint(self.focal_point),
percentage,
@ -159,7 +159,7 @@ impl OutputZoomState {
let percentage = Instant::now().duration_since(*start).as_millis() as f32
/ ANIMATION_DURATION.as_millis() as f32;
ease(Linear, *old_level, self.level, percentage)
ease(EaseInOutCubic, *old_level, self.level, percentage)
} else {
self.level
}

View file

@ -809,14 +809,12 @@ impl XwmHandler for State {
);
}
if !shell.pending_windows.iter().any(|w| w.surface == window) {
let fullscreen = window.is_fullscreen().then(|| seat.active_output());
let maximized = window.is_maximized();
let surface = CosmicSurface::from(window);
shell.pending_windows.push(PendingWindow {
surface,
seat,
fullscreen,
maximized,
fullscreen: None,
maximized: false,
sticky: false,
})
}
@ -916,11 +914,7 @@ impl XwmHandler for State {
// We only allow floating X11 windows to resize themselves. Nothing else
let shell = self.common.shell.read();
if window.is_fullscreen() {
let _ = window.configure(None);
return;
}
// TODO: Fullscreen
if let Some(mapped) = shell
.element_for_surface(&window)
.filter(|mapped| !mapped.is_minimized())